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
autobyteus/llm/api/zhipu_llm.py
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
import logging
|
|
2
|
-
from typing import Optional
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
3
|
from autobyteus.llm.models import LLMModel
|
|
4
4
|
from autobyteus.llm.utils.llm_config import LLMConfig
|
|
5
5
|
from autobyteus.llm.api.openai_compatible_llm import OpenAICompatibleLLM
|
|
6
6
|
|
|
7
7
|
logger = logging.getLogger(__name__)
|
|
8
8
|
|
|
9
|
+
def _normalize_zhipu_extra_params(extra_params: Dict[str, Any]) -> Dict[str, Any]:
|
|
10
|
+
if not extra_params:
|
|
11
|
+
return {}
|
|
12
|
+
|
|
13
|
+
params = dict(extra_params)
|
|
14
|
+
thinking_type = params.pop("thinking_type", None)
|
|
15
|
+
|
|
16
|
+
if thinking_type is not None:
|
|
17
|
+
thinking = dict(params.get("thinking") or {})
|
|
18
|
+
|
|
19
|
+
if thinking_type is not None:
|
|
20
|
+
thinking["type"] = thinking_type
|
|
21
|
+
|
|
22
|
+
params["thinking"] = thinking
|
|
23
|
+
|
|
24
|
+
return params
|
|
25
|
+
|
|
9
26
|
class ZhipuLLM(OpenAICompatibleLLM):
|
|
10
27
|
def __init__(self, model: LLMModel = None, llm_config: LLMConfig = None):
|
|
11
28
|
# Provide defaults if not specified
|
|
12
29
|
if model is None:
|
|
13
|
-
model = LLMModel['glm-4.
|
|
30
|
+
model = LLMModel['glm-4.7']
|
|
14
31
|
if llm_config is None:
|
|
15
32
|
llm_config = LLMConfig()
|
|
16
33
|
|
|
@@ -20,6 +37,8 @@ class ZhipuLLM(OpenAICompatibleLLM):
|
|
|
20
37
|
api_key_env_var="ZHIPU_API_KEY",
|
|
21
38
|
base_url="https://open.bigmodel.cn/api/paas/v4/"
|
|
22
39
|
)
|
|
40
|
+
if self.config and isinstance(self.config.extra_params, dict):
|
|
41
|
+
self.config.extra_params = _normalize_zhipu_extra_params(self.config.extra_params)
|
|
23
42
|
logger.info(f"ZhipuLLM initialized with model: {self.model}")
|
|
24
43
|
|
|
25
44
|
async def cleanup(self):
|
|
@@ -32,76 +32,86 @@ class AutobyteusModelProvider:
|
|
|
32
32
|
|
|
33
33
|
return []
|
|
34
34
|
|
|
35
|
+
@staticmethod
|
|
36
|
+
def get_models() -> List[LLMModel]:
|
|
37
|
+
"""
|
|
38
|
+
Fetches models from all configured Autobyteus hosts and returns them as LLMModel objects.
|
|
39
|
+
"""
|
|
40
|
+
hosts = AutobyteusModelProvider._get_hosts()
|
|
41
|
+
if not hosts:
|
|
42
|
+
logger.info("No Autobyteus LLM server hosts configured. Skipping Autobyteus LLM model discovery.")
|
|
43
|
+
return []
|
|
44
|
+
|
|
45
|
+
all_models = []
|
|
46
|
+
|
|
47
|
+
for host_url in hosts:
|
|
48
|
+
if not AutobyteusModelProvider.is_valid_url(host_url):
|
|
49
|
+
logger.error(f"Invalid Autobyteus host URL: {host_url}, skipping.")
|
|
50
|
+
continue
|
|
51
|
+
|
|
52
|
+
logger.info(f"Discovering Autobyteus models from host: {host_url}")
|
|
53
|
+
client = None
|
|
54
|
+
try:
|
|
55
|
+
# Instantiate client for this specific host
|
|
56
|
+
client = AutobyteusClient(server_url=host_url)
|
|
57
|
+
response = client.get_available_llm_models_sync()
|
|
58
|
+
except Exception as e:
|
|
59
|
+
logger.warning(f"Could not connect or fetch models from Autobyteus server at {host_url}: {e}")
|
|
60
|
+
continue
|
|
61
|
+
finally:
|
|
62
|
+
if client:
|
|
63
|
+
client.sync_client.close()
|
|
64
|
+
|
|
65
|
+
if not AutobyteusModelProvider._validate_server_response(response):
|
|
66
|
+
continue
|
|
67
|
+
|
|
68
|
+
models = response.get('models', [])
|
|
69
|
+
for model_info in models:
|
|
70
|
+
try:
|
|
71
|
+
validation_result = AutobyteusModelProvider._validate_model_info(model_info)
|
|
72
|
+
if not validation_result["valid"]:
|
|
73
|
+
logger.warning(validation_result["message"])
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
llm_config = AutobyteusModelProvider._parse_llm_config(model_info["config"])
|
|
77
|
+
if not llm_config:
|
|
78
|
+
continue
|
|
79
|
+
|
|
80
|
+
llm_model = LLMModel(
|
|
81
|
+
name=model_info["name"],
|
|
82
|
+
value=model_info["value"],
|
|
83
|
+
provider=LLMProvider(model_info["provider"]),
|
|
84
|
+
llm_class=AutobyteusLLM,
|
|
85
|
+
canonical_name=model_info["canonical_name"],
|
|
86
|
+
runtime=LLMRuntime.AUTOBYTEUS,
|
|
87
|
+
host_url=host_url,
|
|
88
|
+
default_config=llm_config
|
|
89
|
+
)
|
|
90
|
+
all_models.append(llm_model)
|
|
91
|
+
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"Failed to create LLMModel for '{model_info.get('name')}' from {host_url}: {e}")
|
|
94
|
+
|
|
95
|
+
return all_models
|
|
96
|
+
|
|
35
97
|
@staticmethod
|
|
36
98
|
def discover_and_register():
|
|
37
99
|
"""Discover and register Autobyteus models from all configured hosts."""
|
|
38
100
|
try:
|
|
39
101
|
from autobyteus.llm.llm_factory import LLMFactory
|
|
40
102
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
logger.info("No Autobyteus LLM server hosts configured. Skipping Autobyteus LLM model discovery.")
|
|
44
|
-
return
|
|
103
|
+
discovered_models = AutobyteusModelProvider.get_models()
|
|
104
|
+
registered_count = 0
|
|
45
105
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
for host_url in hosts:
|
|
49
|
-
if not AutobyteusModelProvider.is_valid_url(host_url):
|
|
50
|
-
logger.error(f"Invalid Autobyteus host URL: {host_url}, skipping.")
|
|
51
|
-
continue
|
|
52
|
-
|
|
53
|
-
logger.info(f"Discovering Autobyteus models from host: {host_url}")
|
|
54
|
-
client = None
|
|
106
|
+
for model in discovered_models:
|
|
55
107
|
try:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
response = client.get_available_llm_models_sync()
|
|
108
|
+
LLMFactory.register_model(model)
|
|
109
|
+
registered_count += 1
|
|
59
110
|
except Exception as e:
|
|
60
|
-
logger.warning(f"
|
|
61
|
-
continue
|
|
62
|
-
finally:
|
|
63
|
-
if client:
|
|
64
|
-
client.sync_client.close()
|
|
65
|
-
|
|
66
|
-
if not AutobyteusModelProvider._validate_server_response(response):
|
|
67
|
-
continue
|
|
68
|
-
|
|
69
|
-
models = response.get('models', [])
|
|
70
|
-
host_registered_count = 0
|
|
71
|
-
for model_info in models:
|
|
72
|
-
try:
|
|
73
|
-
validation_result = AutobyteusModelProvider._validate_model_info(model_info)
|
|
74
|
-
if not validation_result["valid"]:
|
|
75
|
-
logger.warning(validation_result["message"])
|
|
76
|
-
continue
|
|
77
|
-
|
|
78
|
-
llm_config = AutobyteusModelProvider._parse_llm_config(model_info["config"])
|
|
79
|
-
if not llm_config:
|
|
80
|
-
continue
|
|
81
|
-
|
|
82
|
-
llm_model = LLMModel(
|
|
83
|
-
name=model_info["name"],
|
|
84
|
-
value=model_info["value"],
|
|
85
|
-
provider=LLMProvider(model_info["provider"]),
|
|
86
|
-
llm_class=AutobyteusLLM,
|
|
87
|
-
canonical_name=model_info["canonical_name"],
|
|
88
|
-
runtime=LLMRuntime.AUTOBYTEUS,
|
|
89
|
-
host_url=host_url,
|
|
90
|
-
default_config=llm_config
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
LLMFactory.register_model(llm_model)
|
|
94
|
-
host_registered_count += 1
|
|
95
|
-
|
|
96
|
-
except Exception as e:
|
|
97
|
-
logger.error(f"Failed to register Autobyteus model '{model_info.get('name')}' from {host_url}: {e}")
|
|
98
|
-
|
|
99
|
-
if host_registered_count > 0:
|
|
100
|
-
logger.info(f"Registered {host_registered_count} models from Autobyteus host {host_url}")
|
|
101
|
-
total_registered_count += host_registered_count
|
|
111
|
+
logger.warning(f"Failed to register Autobyteus model '{model.name}': {e}")
|
|
102
112
|
|
|
103
|
-
if
|
|
104
|
-
logger.info(f"Finished Autobyteus discovery. Total models registered: {
|
|
113
|
+
if registered_count > 0:
|
|
114
|
+
logger.info(f"Finished Autobyteus discovery. Total models registered: {registered_count}")
|
|
105
115
|
|
|
106
116
|
except Exception as e:
|
|
107
117
|
logger.error(f"An unexpected error occurred during Autobyteus model discovery: {e}", exc_info=True)
|
autobyteus/llm/base_llm.py
CHANGED
|
@@ -26,12 +26,13 @@ class BaseLLM(ABC):
|
|
|
26
26
|
|
|
27
27
|
self._token_usage_extension: TokenUsageTrackingExtension = self.register_extension(TokenUsageTrackingExtension)
|
|
28
28
|
|
|
29
|
-
self.messages: List[Message] = []
|
|
30
29
|
self.system_message = self.config.system_message or self.DEFAULT_SYSTEM_MESSAGE
|
|
31
|
-
self.add_system_message(self.system_message)
|
|
32
30
|
|
|
33
31
|
@property
|
|
34
32
|
def latest_token_usage(self):
|
|
33
|
+
"""Get latest token usage. Returns None if token tracking is disabled."""
|
|
34
|
+
if not self._token_usage_extension.is_enabled:
|
|
35
|
+
return None
|
|
35
36
|
return self._token_usage_extension.latest_token_usage
|
|
36
37
|
|
|
37
38
|
def register_extension(self, extension_class: Type[LLMExtension]) -> LLMExtension:
|
|
@@ -45,42 +46,19 @@ class BaseLLM(ABC):
|
|
|
45
46
|
def get_extension(self, extension_class: Type[LLMExtension]) -> Optional[LLMExtension]:
|
|
46
47
|
return self._extension_registry.get(extension_class)
|
|
47
48
|
|
|
48
|
-
def
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def add_user_message(self, user_message: LLMUserMessage):
|
|
52
|
-
"""
|
|
53
|
-
Adds a user message to history, converting from LLMUserMessage to Message.
|
|
54
|
-
"""
|
|
55
|
-
msg = Message(
|
|
49
|
+
def _build_user_message(self, user_message: LLMUserMessage) -> Message:
|
|
50
|
+
return Message(
|
|
56
51
|
role=MessageRole.USER,
|
|
57
52
|
content=user_message.content,
|
|
58
53
|
image_urls=user_message.image_urls,
|
|
59
54
|
audio_urls=user_message.audio_urls,
|
|
60
|
-
video_urls=user_message.video_urls
|
|
61
|
-
)
|
|
62
|
-
self.messages.append(msg)
|
|
63
|
-
self._trigger_on_user_message_added(msg)
|
|
64
|
-
|
|
65
|
-
def add_assistant_message(self,
|
|
66
|
-
content: Optional[str],
|
|
67
|
-
reasoning_content: Optional[str] = None,
|
|
68
|
-
image_urls: Optional[List[str]] = None,
|
|
69
|
-
audio_urls: Optional[List[str]] = None,
|
|
70
|
-
video_urls: Optional[List[str]] = None):
|
|
71
|
-
"""
|
|
72
|
-
Adds a multimodal assistant message to the conversation history.
|
|
73
|
-
"""
|
|
74
|
-
msg = Message(
|
|
75
|
-
role=MessageRole.ASSISTANT,
|
|
76
|
-
content=content,
|
|
77
|
-
reasoning_content=reasoning_content,
|
|
78
|
-
image_urls=image_urls,
|
|
79
|
-
audio_urls=audio_urls,
|
|
80
|
-
video_urls=video_urls
|
|
55
|
+
video_urls=user_message.video_urls,
|
|
81
56
|
)
|
|
82
|
-
|
|
83
|
-
|
|
57
|
+
|
|
58
|
+
def _build_system_message(self) -> Optional[Message]:
|
|
59
|
+
if not self.system_message:
|
|
60
|
+
return None
|
|
61
|
+
return Message(MessageRole.SYSTEM, content=self.system_message)
|
|
84
62
|
|
|
85
63
|
def configure_system_prompt(self, new_system_prompt: str):
|
|
86
64
|
if not new_system_prompt or not isinstance(new_system_prompt, str):
|
|
@@ -89,51 +67,40 @@ class BaseLLM(ABC):
|
|
|
89
67
|
|
|
90
68
|
self.system_message = new_system_prompt
|
|
91
69
|
self.config.system_message = new_system_prompt
|
|
92
|
-
|
|
93
|
-
system_message_found = False
|
|
94
|
-
for i, msg in enumerate(self.messages):
|
|
95
|
-
if msg.role == MessageRole.SYSTEM:
|
|
96
|
-
self.messages[i] = Message(MessageRole.SYSTEM, new_system_prompt)
|
|
97
|
-
system_message_found = True
|
|
98
|
-
logging.debug(f"Replaced existing system message at index {i}.")
|
|
99
|
-
break
|
|
100
|
-
|
|
101
|
-
if not system_message_found:
|
|
102
|
-
self.messages.insert(0, Message(MessageRole.SYSTEM, new_system_prompt))
|
|
103
|
-
logging.debug("No existing system message found, inserted new one at the beginning.")
|
|
104
|
-
|
|
105
70
|
logging.info(f"LLM instance system prompt updated. New prompt length: {len(new_system_prompt)}")
|
|
106
71
|
|
|
107
|
-
def
|
|
72
|
+
async def _execute_before_hooks(self, messages: List[Message], rendered_payload: Optional[dict] = None, **kwargs) -> None:
|
|
108
73
|
for extension in self._extension_registry.get_all():
|
|
109
|
-
extension.
|
|
74
|
+
await extension.before_invoke(messages, rendered_payload, **kwargs)
|
|
110
75
|
|
|
111
|
-
def
|
|
76
|
+
async def _execute_after_hooks(self, messages: List[Message], response: CompleteResponse = None, **kwargs) -> None:
|
|
112
77
|
for extension in self._extension_registry.get_all():
|
|
113
|
-
extension.
|
|
114
|
-
|
|
115
|
-
async def
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
await self._execute_before_hooks(user_message, **kwargs)
|
|
125
|
-
response = await self._send_user_message_to_llm(user_message, **kwargs)
|
|
126
|
-
await self._execute_after_hooks(user_message, response, **kwargs)
|
|
78
|
+
await extension.after_invoke(messages, response, **kwargs)
|
|
79
|
+
|
|
80
|
+
async def send_messages(
|
|
81
|
+
self,
|
|
82
|
+
messages: List[Message],
|
|
83
|
+
rendered_payload: Optional[dict] = None,
|
|
84
|
+
**kwargs,
|
|
85
|
+
) -> CompleteResponse:
|
|
86
|
+
await self._execute_before_hooks(messages, rendered_payload, **kwargs)
|
|
87
|
+
response = await self._send_messages_to_llm(messages, **kwargs)
|
|
88
|
+
await self._execute_after_hooks(messages, response, **kwargs)
|
|
127
89
|
return response
|
|
128
90
|
|
|
129
|
-
async def
|
|
130
|
-
|
|
91
|
+
async def stream_messages(
|
|
92
|
+
self,
|
|
93
|
+
messages: List[Message],
|
|
94
|
+
rendered_payload: Optional[dict] = None,
|
|
95
|
+
**kwargs,
|
|
96
|
+
) -> AsyncGenerator[ChunkResponse, None]:
|
|
97
|
+
await self._execute_before_hooks(messages, rendered_payload, **kwargs)
|
|
131
98
|
|
|
132
99
|
accumulated_content = ""
|
|
133
100
|
accumulated_reasoning = ""
|
|
134
101
|
final_chunk = None
|
|
135
|
-
|
|
136
|
-
async for chunk in self.
|
|
102
|
+
|
|
103
|
+
async for chunk in self._stream_messages_to_llm(messages, **kwargs):
|
|
137
104
|
if chunk.content:
|
|
138
105
|
accumulated_content += chunk.content
|
|
139
106
|
if chunk.reasoning:
|
|
@@ -146,34 +113,72 @@ class BaseLLM(ABC):
|
|
|
146
113
|
complete_response = CompleteResponse(
|
|
147
114
|
content=accumulated_content,
|
|
148
115
|
reasoning=accumulated_reasoning if accumulated_reasoning else None,
|
|
149
|
-
usage=final_chunk.usage if final_chunk else None
|
|
116
|
+
usage=final_chunk.usage if final_chunk else None,
|
|
150
117
|
)
|
|
151
|
-
|
|
152
|
-
await self._execute_after_hooks(user_message, complete_response, **kwargs)
|
|
153
118
|
|
|
154
|
-
|
|
119
|
+
await self._execute_after_hooks(messages, complete_response, **kwargs)
|
|
120
|
+
|
|
121
|
+
async def send_user_message(self, user_message: LLMUserMessage, **kwargs) -> CompleteResponse:
|
|
122
|
+
messages: List[Message] = []
|
|
123
|
+
system_message = self._build_system_message()
|
|
124
|
+
if system_message:
|
|
125
|
+
messages.append(system_message)
|
|
126
|
+
messages.append(self._build_user_message(user_message))
|
|
127
|
+
return await self.send_messages(messages, **kwargs)
|
|
128
|
+
|
|
129
|
+
async def stream_user_message(
|
|
130
|
+
self, user_message: LLMUserMessage, **kwargs
|
|
131
|
+
) -> AsyncGenerator[ChunkResponse, None]:
|
|
132
|
+
messages: List[Message] = []
|
|
133
|
+
system_message = self._build_system_message()
|
|
134
|
+
if system_message:
|
|
135
|
+
messages.append(system_message)
|
|
136
|
+
messages.append(self._build_user_message(user_message))
|
|
137
|
+
async for chunk in self.stream_messages(messages, **kwargs):
|
|
138
|
+
yield chunk
|
|
139
|
+
|
|
155
140
|
async def _send_user_message_to_llm(self, user_message: LLMUserMessage, **kwargs) -> CompleteResponse:
|
|
141
|
+
messages: List[Message] = []
|
|
142
|
+
system_message = self._build_system_message()
|
|
143
|
+
if system_message:
|
|
144
|
+
messages.append(system_message)
|
|
145
|
+
messages.append(self._build_user_message(user_message))
|
|
146
|
+
return await self._send_messages_to_llm(messages, **kwargs)
|
|
147
|
+
|
|
148
|
+
async def _stream_user_message_to_llm(
|
|
149
|
+
self, user_message: LLMUserMessage, **kwargs
|
|
150
|
+
) -> AsyncGenerator[ChunkResponse, None]:
|
|
151
|
+
messages: List[Message] = []
|
|
152
|
+
system_message = self._build_system_message()
|
|
153
|
+
if system_message:
|
|
154
|
+
messages.append(system_message)
|
|
155
|
+
messages.append(self._build_user_message(user_message))
|
|
156
|
+
async for chunk in self._stream_messages_to_llm(messages, **kwargs):
|
|
157
|
+
yield chunk
|
|
158
|
+
|
|
159
|
+
@abstractmethod
|
|
160
|
+
async def _send_messages_to_llm(self, messages: List[Message], **kwargs) -> CompleteResponse:
|
|
156
161
|
"""
|
|
157
|
-
Abstract method for sending a
|
|
158
|
-
|
|
162
|
+
Abstract method for sending a list of messages to an LLM. Must be implemented by subclasses.
|
|
163
|
+
|
|
159
164
|
Args:
|
|
160
|
-
|
|
165
|
+
messages (List[Message]): The message list to send.
|
|
161
166
|
**kwargs: Additional arguments for LLM-specific usage.
|
|
162
|
-
|
|
167
|
+
|
|
163
168
|
Returns:
|
|
164
169
|
CompleteResponse: The complete response from the LLM.
|
|
165
170
|
"""
|
|
166
171
|
pass
|
|
167
172
|
|
|
168
173
|
@abstractmethod
|
|
169
|
-
async def
|
|
174
|
+
async def _stream_messages_to_llm(self, messages: List[Message], **kwargs) -> AsyncGenerator[ChunkResponse, None]:
|
|
170
175
|
"""
|
|
171
|
-
Abstract method for streaming a
|
|
172
|
-
|
|
176
|
+
Abstract method for streaming a response from an LLM. Must be implemented by subclasses.
|
|
177
|
+
|
|
173
178
|
Args:
|
|
174
|
-
|
|
179
|
+
messages (List[Message]): The message list to send.
|
|
175
180
|
**kwargs: Additional arguments for LLM-specific usage.
|
|
176
|
-
|
|
181
|
+
|
|
177
182
|
Yields:
|
|
178
183
|
AsyncGenerator[ChunkResponse, None]: Streaming chunks from the LLM response.
|
|
179
184
|
"""
|
|
@@ -183,4 +188,3 @@ class BaseLLM(ABC):
|
|
|
183
188
|
for extension in self._extension_registry.get_all():
|
|
184
189
|
await extension.cleanup()
|
|
185
190
|
self._extension_registry.clear()
|
|
186
|
-
self.messages = []
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/llm/converters/__init__.py
|
|
2
|
+
"""
|
|
3
|
+
LLM provider-specific converters.
|
|
4
|
+
|
|
5
|
+
These converters transform provider-specific data formats into
|
|
6
|
+
normalized internal representations.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .openai_tool_call_converter import convert_openai_tool_calls
|
|
10
|
+
from .gemini_tool_call_converter import convert_gemini_tool_calls
|
|
11
|
+
from .anthropic_tool_call_converter import convert_anthropic_tool_call
|
|
12
|
+
from .mistral_tool_call_converter import convert_mistral_tool_calls
|
|
13
|
+
|
|
14
|
+
__all__ = ["convert_openai_tool_calls", "convert_gemini_tool_calls", "convert_anthropic_tool_call", "convert_mistral_tool_calls"]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import List, Optional, Any
|
|
2
|
+
from autobyteus.llm.utils.tool_call_delta import ToolCallDelta
|
|
3
|
+
|
|
4
|
+
# Anthropic event types are typically simple objects or dicts from the SDK stream
|
|
5
|
+
# The SDK yields `MessageStreamEvent` objects.
|
|
6
|
+
|
|
7
|
+
def convert_anthropic_tool_call(event: Any) -> Optional[List[ToolCallDelta]]:
|
|
8
|
+
"""
|
|
9
|
+
Convert an Anthropic stream event into ToolCallDelta objects.
|
|
10
|
+
|
|
11
|
+
Handles:
|
|
12
|
+
- ContentBlockStartEvent (type='content_block_start') -> Tool Name + ID
|
|
13
|
+
- ContentBlockDeltaEvent (type='content_block_delta') -> Arguments Delta
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
# Handle ContentBlockStartEvent (Start of tool use)
|
|
17
|
+
# event.content_block.type == 'tool_use'
|
|
18
|
+
if event.type == "content_block_start":
|
|
19
|
+
if event.content_block.type == "tool_use":
|
|
20
|
+
return [ToolCallDelta(
|
|
21
|
+
index=event.index, # Anthropic provides index
|
|
22
|
+
call_id=event.content_block.id,
|
|
23
|
+
name=event.content_block.name,
|
|
24
|
+
arguments_delta=None # No args yet
|
|
25
|
+
)]
|
|
26
|
+
|
|
27
|
+
# Handle ContentBlockDeltaEvent (JSON args update)
|
|
28
|
+
elif event.type == "content_block_delta":
|
|
29
|
+
if event.delta.type == "input_json_delta":
|
|
30
|
+
return [ToolCallDelta(
|
|
31
|
+
index=event.index, # Anthropic provides index matching the start event
|
|
32
|
+
call_id=None,
|
|
33
|
+
name=None,
|
|
34
|
+
arguments_delta=event.delta.partial_json
|
|
35
|
+
)]
|
|
36
|
+
|
|
37
|
+
return None
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from typing import List, Optional, Any
|
|
2
|
+
from autobyteus.llm.utils.tool_call_delta import ToolCallDelta
|
|
3
|
+
from google.genai import types as genai_types
|
|
4
|
+
import json
|
|
5
|
+
|
|
6
|
+
def convert_gemini_tool_calls(part: Any) -> Optional[List[ToolCallDelta]]:
|
|
7
|
+
"""
|
|
8
|
+
Convert a Gemini stream part (which might be a functionCall) into ToolCallDelta objects.
|
|
9
|
+
|
|
10
|
+
Gemini 'functionCall' usually comes as a complete object in the parts list,
|
|
11
|
+
but we treat it as a delta to fit the unified streaming model.
|
|
12
|
+
"""
|
|
13
|
+
# Check if the part has a function_call
|
|
14
|
+
# The SDK structure for part usually has a 'function_call' attribute
|
|
15
|
+
|
|
16
|
+
# Note: genai_types.Part might have function_call (FunctionCall)
|
|
17
|
+
|
|
18
|
+
# Safety check for attribute existence
|
|
19
|
+
if not hasattr(part, "function_call") or not part.function_call:
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
fc = part.function_call
|
|
23
|
+
|
|
24
|
+
# Gemini provides the full arguments as a dict in the 'args' attribute
|
|
25
|
+
# We serialize this back to JSON string for the delta, because our unified
|
|
26
|
+
# ToolCallDelta expects string deltas for arguments.
|
|
27
|
+
# Since we get the full args at once, this is a "complete" delta.
|
|
28
|
+
|
|
29
|
+
# Note: 'args' is a dictionary.
|
|
30
|
+
arguments_json = json.dumps(fc.args) if fc.args else "{}"
|
|
31
|
+
|
|
32
|
+
# We use a fixed index 0 because Gemini typically emits one function call per candidate part?
|
|
33
|
+
# Actually Gemini can return multiple function calls in parallel tool use?
|
|
34
|
+
# But usually they are in separate parts or candidates.
|
|
35
|
+
# For now, we assume implicit index 0 for the part itself.
|
|
36
|
+
# If parallel tool calling is supported via multiple parts, the caller loop needs to handle indexing
|
|
37
|
+
# if it's not provided by the SDK.
|
|
38
|
+
# However, ToolCallDelta requires an index. We'll default to 0.
|
|
39
|
+
# If the caller iterates parts, it might need to assign indices.
|
|
40
|
+
# But wait, ToolCallDelta logic merges by index. If we always return index 0 for distinct parts, they merge.
|
|
41
|
+
# We might need to generate a unique index or rely on the caller to offset it.
|
|
42
|
+
# BUT, Gemini streaming chunks usually contain ONE part at a time.
|
|
43
|
+
# If we treat each function_call part as a NEW tool call, we need a way to distinguish parallel ones?
|
|
44
|
+
# Or maybe we just generate a unique call_id if one isn't present.
|
|
45
|
+
# Gemini function calls don't always have IDs in the stream?
|
|
46
|
+
# Let's check `fc.name` and `fc.args`.
|
|
47
|
+
|
|
48
|
+
# For simplicity, if we get a full function call, we return one delta that has EVERYTHING.
|
|
49
|
+
# The unified handler will assume it's a new call if index is new... or if it's the first time
|
|
50
|
+
# seeing this index.
|
|
51
|
+
|
|
52
|
+
return [ToolCallDelta(
|
|
53
|
+
index=0, # Assuming single tool call per part context for now
|
|
54
|
+
call_id=None, # Gemini doesn't always provide call ID in stream? We'll rely on handler to generate one.
|
|
55
|
+
name=fc.name,
|
|
56
|
+
arguments_delta=arguments_json
|
|
57
|
+
)]
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from typing import List, Optional, Any
|
|
2
|
+
from autobyteus.llm.utils.tool_call_delta import ToolCallDelta
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
def convert_mistral_tool_calls(tool_calls: List[Any]) -> Optional[List[ToolCallDelta]]:
|
|
8
|
+
"""
|
|
9
|
+
Convert Mistral streaming tool calls (similar to OpenAI) into ToolCallDelta objects.
|
|
10
|
+
"""
|
|
11
|
+
if not tool_calls:
|
|
12
|
+
return None
|
|
13
|
+
|
|
14
|
+
deltas = []
|
|
15
|
+
for tool_call in tool_calls:
|
|
16
|
+
# Mistral SDK 'ToolCall' or dict in delta
|
|
17
|
+
# Usually has: index, id, function (name, arguments)
|
|
18
|
+
|
|
19
|
+
index = tool_call.get('index', 0) if isinstance(tool_call, dict) else getattr(tool_call, 'index', 0)
|
|
20
|
+
call_id = tool_call.get('id', None) if isinstance(tool_call, dict) else getattr(tool_call, 'id', None)
|
|
21
|
+
|
|
22
|
+
function = tool_call.get('function', None) if isinstance(tool_call, dict) else getattr(tool_call, 'function', None)
|
|
23
|
+
name = None
|
|
24
|
+
arguments = None
|
|
25
|
+
|
|
26
|
+
if function:
|
|
27
|
+
name = function.get('name', None) if isinstance(function, dict) else getattr(function, 'name', None)
|
|
28
|
+
arguments = function.get('arguments', None) if isinstance(function, dict) else getattr(function, 'arguments', None)
|
|
29
|
+
|
|
30
|
+
deltas.append(ToolCallDelta(
|
|
31
|
+
index=index,
|
|
32
|
+
call_id=call_id,
|
|
33
|
+
name=name,
|
|
34
|
+
arguments_delta=arguments
|
|
35
|
+
))
|
|
36
|
+
|
|
37
|
+
return deltas
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/llm/converters/openai_tool_call_converter.py
|
|
2
|
+
"""
|
|
3
|
+
Converter for OpenAI SDK tool call deltas to normalized ToolCallDelta format.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from typing import List, Optional
|
|
7
|
+
from autobyteus.llm.utils.tool_call_delta import ToolCallDelta
|
|
8
|
+
|
|
9
|
+
# Type checking import for OpenAI SDK types
|
|
10
|
+
try:
|
|
11
|
+
from openai.types.chat.chat_completion_chunk import ChoiceDeltaToolCall
|
|
12
|
+
except ImportError:
|
|
13
|
+
ChoiceDeltaToolCall = None # type: ignore
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def convert_openai_tool_calls(delta_tool_calls: Optional[List]) -> Optional[List[ToolCallDelta]]:
|
|
17
|
+
"""
|
|
18
|
+
Convert OpenAI SDK tool call deltas to normalized ToolCallDelta objects.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
delta_tool_calls: List of ChoiceDeltaToolCall from OpenAI SDK, or None.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
List of normalized ToolCallDelta objects, or None if input is None/empty.
|
|
25
|
+
"""
|
|
26
|
+
if not delta_tool_calls:
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
result = []
|
|
30
|
+
for tc in delta_tool_calls:
|
|
31
|
+
# Extract fields from OpenAI's ChoiceDeltaToolCall
|
|
32
|
+
result.append(ToolCallDelta(
|
|
33
|
+
index=tc.index,
|
|
34
|
+
call_id=tc.id if tc.id else None,
|
|
35
|
+
name=tc.function.name if tc.function and tc.function.name else None,
|
|
36
|
+
arguments_delta=tc.function.arguments if tc.function and tc.function.arguments else None,
|
|
37
|
+
))
|
|
38
|
+
return result
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from abc import ABC, abstractmethod
|
|
2
|
-
from typing import List, Optional, TYPE_CHECKING
|
|
2
|
+
from typing import List, Optional, TYPE_CHECKING, Any
|
|
3
|
+
|
|
3
4
|
from autobyteus.llm.utils.messages import Message
|
|
4
5
|
from autobyteus.llm.utils.response_types import CompleteResponse
|
|
5
|
-
from autobyteus.llm.user_message import LLMUserMessage
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from autobyteus.llm.base_llm import BaseLLM
|
|
@@ -13,32 +13,26 @@ class LLMExtension(ABC):
|
|
|
13
13
|
|
|
14
14
|
@abstractmethod
|
|
15
15
|
async def before_invoke(
|
|
16
|
-
self,
|
|
16
|
+
self, messages: List[Message], rendered_payload: Optional[Any] = None, **kwargs
|
|
17
17
|
) -> None:
|
|
18
18
|
"""
|
|
19
|
-
Called before invoking the LLM with
|
|
19
|
+
Called before invoking the LLM with explicit messages.
|
|
20
20
|
"""
|
|
21
21
|
pass
|
|
22
22
|
|
|
23
23
|
@abstractmethod
|
|
24
24
|
async def after_invoke(
|
|
25
|
-
self,
|
|
25
|
+
self, messages: List[Message], response: CompleteResponse = None, **kwargs
|
|
26
26
|
) -> None:
|
|
27
27
|
"""
|
|
28
28
|
Called after receiving the response from the LLM.
|
|
29
29
|
|
|
30
30
|
Args:
|
|
31
|
-
|
|
31
|
+
messages: The explicit prompt messages used for invocation.
|
|
32
32
|
response: Complete response including content and usage information.
|
|
33
33
|
kwargs: Additional arguments.
|
|
34
34
|
"""
|
|
35
35
|
pass
|
|
36
36
|
|
|
37
|
-
def on_user_message_added(self, message: Message):
|
|
38
|
-
pass
|
|
39
|
-
|
|
40
|
-
def on_assistant_message_added(self, message: Message):
|
|
41
|
-
pass
|
|
42
|
-
|
|
43
37
|
async def cleanup(self) -> None:
|
|
44
38
|
pass
|