autobyteus 1.2.0__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 +23 -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 +74 -60
- 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/message/send_message_to.py +5 -4
- 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 -178
- 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 -198
- autobyteus/agent/streaming/stream_events.py +3 -128
- 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 +5 -6
- autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +15 -15
- 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 +11 -8
- 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 +10 -10
- autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +7 -7
- autobyteus/agent_team/streaming/agent_team_stream_events.py +11 -11
- 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/activation_policy.py +1 -1
- autobyteus/agent_team/task_notification/system_event_driven_agent_task_notifier.py +22 -22
- autobyteus/agent_team/task_notification/task_notification_mode.py +20 -1
- autobyteus/agent_team/utils/wait_for_idle.py +4 -4
- autobyteus/cli/agent_cli.py +18 -10
- autobyteus/cli/agent_team_tui/app.py +18 -15
- autobyteus/cli/agent_team_tui/state.py +21 -23
- autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
- autobyteus/cli/agent_team_tui/widgets/focus_pane.py +146 -39
- autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
- autobyteus/cli/agent_team_tui/widgets/shared.py +26 -26
- autobyteus/cli/agent_team_tui/widgets/{task_board_panel.py → task_plan_panel.py} +5 -5
- 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 +15 -21
- 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/__init__.py +3 -2
- autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
- autobyteus/multimedia/audio/api/gemini_audio_client.py +108 -16
- autobyteus/multimedia/audio/api/openai_audio_client.py +112 -0
- autobyteus/multimedia/audio/audio_client_factory.py +84 -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/__init__.py +43 -20
- autobyteus/task_management/{base_task_board.py → base_task_plan.py} +16 -13
- autobyteus/task_management/converters/__init__.py +2 -2
- autobyteus/task_management/converters/{task_board_converter.py → task_plan_converter.py} +13 -13
- autobyteus/task_management/events.py +7 -7
- autobyteus/task_management/{in_memory_task_board.py → in_memory_task_plan.py} +34 -22
- autobyteus/task_management/schemas/__init__.py +3 -0
- autobyteus/task_management/schemas/task_status_report.py +2 -2
- autobyteus/task_management/schemas/todo_definition.py +15 -0
- autobyteus/task_management/todo.py +29 -0
- autobyteus/task_management/todo_list.py +75 -0
- autobyteus/task_management/tools/__init__.py +24 -8
- autobyteus/task_management/tools/task_tools/__init__.py +19 -0
- autobyteus/task_management/tools/{assign_task_to.py → task_tools/assign_task_to.py} +18 -18
- autobyteus/task_management/tools/{publish_task.py → task_tools/create_task.py} +16 -18
- autobyteus/task_management/tools/{publish_tasks.py → task_tools/create_tasks.py} +19 -19
- autobyteus/task_management/tools/{get_my_tasks.py → task_tools/get_my_tasks.py} +15 -15
- autobyteus/task_management/tools/{get_task_board_status.py → task_tools/get_task_plan_status.py} +16 -16
- autobyteus/task_management/tools/{update_task_status.py → task_tools/update_task_status.py} +16 -16
- autobyteus/task_management/tools/todo_tools/__init__.py +18 -0
- autobyteus/task_management/tools/todo_tools/add_todo.py +78 -0
- autobyteus/task_management/tools/todo_tools/create_todo_list.py +79 -0
- autobyteus/task_management/tools/todo_tools/get_todo_list.py +55 -0
- autobyteus/task_management/tools/todo_tools/update_todo_status.py +85 -0
- autobyteus/tools/__init__.py +43 -52
- autobyteus/tools/base_tool.py +7 -0
- autobyteus/tools/file/__init__.py +9 -0
- autobyteus/tools/file/patch_file.py +149 -0
- autobyteus/tools/file/{file_reader.py → read_file.py} +38 -7
- autobyteus/tools/file/{file_writer.py → write_file.py} +7 -4
- autobyteus/tools/functional_tool.py +53 -14
- 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/tool.py +3 -3
- autobyteus/tools/mcp/tool_registrar.py +5 -2
- autobyteus/tools/mcp/types.py +61 -0
- autobyteus/tools/multimedia/__init__.py +2 -1
- autobyteus/tools/multimedia/audio_tools.py +72 -19
- autobyteus/tools/{download_media_tool.py → multimedia/download_media_tool.py} +21 -7
- autobyteus/tools/multimedia/image_tools.py +248 -64
- autobyteus/tools/multimedia/media_reader_tool.py +1 -1
- 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 +108 -14
- autobyteus/tools/registry/tool_registry.py +29 -0
- autobyteus/tools/search/__init__.py +17 -0
- autobyteus/tools/search/base_strategy.py +35 -0
- autobyteus/tools/search/client.py +24 -0
- autobyteus/tools/search/factory.py +81 -0
- autobyteus/tools/search/google_cse_strategy.py +68 -0
- autobyteus/tools/search/providers.py +10 -0
- autobyteus/tools/search/serpapi_strategy.py +65 -0
- autobyteus/tools/search/serper_strategy.py +87 -0
- autobyteus/tools/search_tool.py +83 -0
- 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/tool_meta.py +4 -24
- 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 +4 -11
- 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.0.dist-info → autobyteus-1.2.3.dist-info}/WHEEL +1 -1
- {autobyteus-1.2.0.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/person/examples/sample_persons.py +0 -14
- autobyteus/person/examples/sample_roles.py +0 -14
- autobyteus/person/person.py +0 -29
- autobyteus/person/role.py +0 -14
- 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/__init__.py +0 -0
- 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/__init__.py +0 -0
- 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 -80
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -97
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -165
- autobyteus/tools/browser/standalone/webpage_reader.py +0 -101
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -101
- autobyteus/tools/file/file_editor.py +0 -200
- autobyteus/tools/google_search.py +0 -149
- autobyteus/tools/timer.py +0 -171
- 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.0.dist-info/METADATA +0 -205
- autobyteus-1.2.0.dist-info/RECORD +0 -496
- examples/__init__.py +0 -1
- examples/agent_team/__init__.py +0 -1
- examples/discover_phase_transitions.py +0 -104
- 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/{person → skills}/__init__.py +0 -0
- /autobyteus/{person/examples → tools/skill}/__init__.py +0 -0
- {autobyteus-1.2.0.dist-info → autobyteus-1.2.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
import re
|
|
3
|
-
import html
|
|
4
|
-
from typing import TYPE_CHECKING, Dict, Any, List
|
|
5
|
-
from dataclasses import dataclass, field
|
|
6
|
-
|
|
7
|
-
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
8
|
-
from .base_parser import BaseToolUsageParser
|
|
9
|
-
|
|
10
|
-
if TYPE_CHECKING:
|
|
11
|
-
from autobyteus.llm.utils.response_types import CompleteResponse
|
|
12
|
-
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
|
-
# A unique UUID to use as an internal key for storing text content.
|
|
16
|
-
# This prevents any potential collision with user-provided argument names.
|
|
17
|
-
_INTERNAL_TEXT_KEY_UUID = "4e1a3b1e-3b2a-4d3c-9a8b-2a1c2b3d4e5f"
|
|
18
|
-
|
|
19
|
-
# --- Internal Arguments Parser with State Machine ---
|
|
20
|
-
# This entire section is now encapsulated in its own class for clarity.
|
|
21
|
-
|
|
22
|
-
class _XmlArgumentsParser:
|
|
23
|
-
"""
|
|
24
|
-
A dedicated parser for the XML content within an <arguments> tag.
|
|
25
|
-
It encapsulates the state machine and all related logic, separating it
|
|
26
|
-
from the higher-level tool-finding logic.
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
# --- Nested State Machine Components ---
|
|
30
|
-
|
|
31
|
-
@dataclass
|
|
32
|
-
class _ParsingContext:
|
|
33
|
-
"""Holds the shared state for the parsing process."""
|
|
34
|
-
parser: '_XmlArgumentsParser'
|
|
35
|
-
input_string: str
|
|
36
|
-
cursor: int = 0
|
|
37
|
-
stack: List[Any] = field(default_factory=list)
|
|
38
|
-
content_buffer: str = ""
|
|
39
|
-
|
|
40
|
-
def __post_init__(self):
|
|
41
|
-
self.stack.append({}) # Root of arguments is a dictionary
|
|
42
|
-
|
|
43
|
-
def is_eof(self) -> bool:
|
|
44
|
-
return self.cursor >= len(self.input_string)
|
|
45
|
-
|
|
46
|
-
def append_to_buffer(self, text: str):
|
|
47
|
-
self.content_buffer += text
|
|
48
|
-
|
|
49
|
-
def commit_content_buffer(self):
|
|
50
|
-
if self.content_buffer:
|
|
51
|
-
self.parser._commit_content(self.stack, self.content_buffer)
|
|
52
|
-
self.content_buffer = ""
|
|
53
|
-
|
|
54
|
-
class _ParserState:
|
|
55
|
-
"""Abstract base class for a state in our parser's state machine."""
|
|
56
|
-
def handle(self, context: '_XmlArgumentsParser._ParsingContext') -> '_XmlArgumentsParser._ParserState':
|
|
57
|
-
raise NotImplementedError
|
|
58
|
-
|
|
59
|
-
class _ParsingContentState(_ParserState):
|
|
60
|
-
"""Handles accumulation of character data between tags."""
|
|
61
|
-
def handle(self, context: '_XmlArgumentsParser._ParsingContext') -> '_XmlArgumentsParser._ParserState':
|
|
62
|
-
if context.is_eof():
|
|
63
|
-
return None
|
|
64
|
-
|
|
65
|
-
next_tag_start = context.input_string.find('<', context.cursor)
|
|
66
|
-
|
|
67
|
-
if next_tag_start == -1:
|
|
68
|
-
context.append_to_buffer(context.input_string[context.cursor:])
|
|
69
|
-
context.cursor = len(context.input_string)
|
|
70
|
-
return self
|
|
71
|
-
|
|
72
|
-
is_valid_tag = False
|
|
73
|
-
if next_tag_start + 1 < len(context.input_string):
|
|
74
|
-
next_char = context.input_string[next_tag_start + 1]
|
|
75
|
-
if next_char.isalpha() or next_char == '/':
|
|
76
|
-
is_valid_tag = True
|
|
77
|
-
|
|
78
|
-
if is_valid_tag:
|
|
79
|
-
content_before_tag = context.input_string[context.cursor:next_tag_start]
|
|
80
|
-
context.append_to_buffer(content_before_tag)
|
|
81
|
-
context.commit_content_buffer()
|
|
82
|
-
context.cursor = next_tag_start
|
|
83
|
-
return self.parser._ParsingTagState(self.parser)
|
|
84
|
-
else:
|
|
85
|
-
content_with_char = context.input_string[context.cursor : next_tag_start + 1]
|
|
86
|
-
context.append_to_buffer(content_with_char)
|
|
87
|
-
context.cursor = next_tag_start + 1
|
|
88
|
-
return self
|
|
89
|
-
|
|
90
|
-
def __init__(self, parser: '_XmlArgumentsParser'):
|
|
91
|
-
self.parser = parser
|
|
92
|
-
|
|
93
|
-
class _ParsingTagState(_ParserState):
|
|
94
|
-
"""Handles parsing of a tag, from '<' to '>'."""
|
|
95
|
-
def handle(self, context: '_XmlArgumentsParser._ParsingContext') -> '_XmlArgumentsParser._ParserState':
|
|
96
|
-
tag_content_end = context.input_string.find('>', context.cursor)
|
|
97
|
-
if tag_content_end == -1:
|
|
98
|
-
context.append_to_buffer(context.input_string[context.cursor:])
|
|
99
|
-
context.cursor = len(context.input_string)
|
|
100
|
-
return self.parser._ParsingContentState(self.parser)
|
|
101
|
-
|
|
102
|
-
tag_content = context.input_string[context.cursor + 1 : tag_content_end]
|
|
103
|
-
context.parser.process_tag(tag_content, context)
|
|
104
|
-
|
|
105
|
-
context.cursor = tag_content_end + 1
|
|
106
|
-
return self.parser._ParsingContentState(self.parser)
|
|
107
|
-
|
|
108
|
-
def __init__(self, parser: '_XmlArgumentsParser'):
|
|
109
|
-
self.parser = parser
|
|
110
|
-
|
|
111
|
-
# --- Parser Implementation ---
|
|
112
|
-
|
|
113
|
-
def __init__(self, xml_string: str):
|
|
114
|
-
self.xml_string = xml_string
|
|
115
|
-
|
|
116
|
-
def parse(self) -> Dict[str, Any]:
|
|
117
|
-
"""Drives the state machine to parse the XML string."""
|
|
118
|
-
context = self._ParsingContext(parser=self, input_string=self.xml_string)
|
|
119
|
-
state = self._ParsingContentState(self)
|
|
120
|
-
|
|
121
|
-
while state and not context.is_eof():
|
|
122
|
-
state = state.handle(context)
|
|
123
|
-
|
|
124
|
-
context.commit_content_buffer()
|
|
125
|
-
|
|
126
|
-
final_args = context.stack[0]
|
|
127
|
-
self._cleanup_internal_keys(final_args)
|
|
128
|
-
final_args = self._decode_entities_inplace(final_args)
|
|
129
|
-
return final_args
|
|
130
|
-
|
|
131
|
-
def process_tag(self, tag_content: str, context: '_ParsingContext'):
|
|
132
|
-
STRUCTURAL_TAGS = {'arg', 'item'}
|
|
133
|
-
stripped_content = tag_content.strip()
|
|
134
|
-
if not stripped_content:
|
|
135
|
-
context.append_to_buffer(f"<{tag_content}>")
|
|
136
|
-
return
|
|
137
|
-
|
|
138
|
-
is_closing = stripped_content.startswith('/')
|
|
139
|
-
tag_name = (stripped_content[1:] if is_closing else stripped_content).split(' ')[0]
|
|
140
|
-
|
|
141
|
-
if tag_name in STRUCTURAL_TAGS:
|
|
142
|
-
if is_closing:
|
|
143
|
-
self._handle_closing_tag(context.stack)
|
|
144
|
-
else:
|
|
145
|
-
self._handle_opening_tag(context.stack, tag_content)
|
|
146
|
-
else:
|
|
147
|
-
context.append_to_buffer(f"<{tag_content}>")
|
|
148
|
-
|
|
149
|
-
def _commit_content(self, stack: List[Any], content: str):
|
|
150
|
-
trimmed_content = content.strip()
|
|
151
|
-
if not trimmed_content and '<' not in content and '>' not in content:
|
|
152
|
-
return
|
|
153
|
-
|
|
154
|
-
top = stack[-1]
|
|
155
|
-
if isinstance(top, dict):
|
|
156
|
-
top[_INTERNAL_TEXT_KEY_UUID] = top.get(_INTERNAL_TEXT_KEY_UUID, '') + content
|
|
157
|
-
|
|
158
|
-
def _handle_opening_tag(self, stack: List[Any], tag_content: str):
|
|
159
|
-
parent = stack[-1]
|
|
160
|
-
|
|
161
|
-
if tag_content.strip().startswith('arg'):
|
|
162
|
-
name_match = re.search(r'name="([^"]+)"', tag_content)
|
|
163
|
-
if name_match and isinstance(parent, dict):
|
|
164
|
-
arg_name = name_match.group(1)
|
|
165
|
-
new_container = {}
|
|
166
|
-
parent[arg_name] = new_container
|
|
167
|
-
stack.append(new_container)
|
|
168
|
-
|
|
169
|
-
elif tag_content.strip().startswith('item'):
|
|
170
|
-
if isinstance(parent, dict):
|
|
171
|
-
grandparent = stack[-2]
|
|
172
|
-
parent_key = next((k for k, v in grandparent.items() if v is parent), None)
|
|
173
|
-
if parent_key:
|
|
174
|
-
new_list = []
|
|
175
|
-
grandparent[parent_key] = new_list
|
|
176
|
-
stack[-1] = new_list
|
|
177
|
-
parent = new_list
|
|
178
|
-
|
|
179
|
-
if isinstance(parent, list):
|
|
180
|
-
new_item_container = {}
|
|
181
|
-
parent.append(new_item_container)
|
|
182
|
-
stack.append(new_item_container)
|
|
183
|
-
|
|
184
|
-
def _handle_closing_tag(self, stack: List[Any]):
|
|
185
|
-
if len(stack) > 1:
|
|
186
|
-
top = stack.pop()
|
|
187
|
-
parent = stack[-1]
|
|
188
|
-
|
|
189
|
-
is_primitive = False
|
|
190
|
-
if isinstance(top, dict):
|
|
191
|
-
keys = top.keys()
|
|
192
|
-
if not keys or (len(keys) == 1 and _INTERNAL_TEXT_KEY_UUID in keys):
|
|
193
|
-
is_primitive = True
|
|
194
|
-
|
|
195
|
-
if is_primitive:
|
|
196
|
-
value = top.get(_INTERNAL_TEXT_KEY_UUID, '')
|
|
197
|
-
if isinstance(parent, list):
|
|
198
|
-
try:
|
|
199
|
-
idx = parent.index(top)
|
|
200
|
-
parent[idx] = value
|
|
201
|
-
except ValueError:
|
|
202
|
-
logger.warning("Could not find item to collapse in parent list.")
|
|
203
|
-
elif isinstance(parent, dict):
|
|
204
|
-
parent_key = next((k for k, v in parent.items() if v is top), None)
|
|
205
|
-
if parent_key:
|
|
206
|
-
parent[parent_key] = value
|
|
207
|
-
|
|
208
|
-
def _cleanup_internal_keys(self, data: Any):
|
|
209
|
-
if isinstance(data, dict):
|
|
210
|
-
if _INTERNAL_TEXT_KEY_UUID in data and len(data) > 1:
|
|
211
|
-
del data[_INTERNAL_TEXT_KEY_UUID]
|
|
212
|
-
for value in data.values():
|
|
213
|
-
self._cleanup_internal_keys(value)
|
|
214
|
-
elif isinstance(data, list):
|
|
215
|
-
for item in data:
|
|
216
|
-
self._cleanup_internal_keys(item)
|
|
217
|
-
|
|
218
|
-
def _decode_entities_inplace(self, data: Any):
|
|
219
|
-
if isinstance(data, dict):
|
|
220
|
-
for key, value in list(data.items()):
|
|
221
|
-
data[key] = self._decode_entities_inplace(value)
|
|
222
|
-
return data
|
|
223
|
-
if isinstance(data, list):
|
|
224
|
-
for index, item in enumerate(data):
|
|
225
|
-
data[index] = self._decode_entities_inplace(item)
|
|
226
|
-
return data
|
|
227
|
-
if isinstance(data, str):
|
|
228
|
-
return html.unescape(data)
|
|
229
|
-
return data
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
# --- Main Parser Class ---
|
|
233
|
-
|
|
234
|
-
class DefaultXmlToolUsageParser(BaseToolUsageParser):
|
|
235
|
-
"""
|
|
236
|
-
Parses LLM responses for tool usage commands formatted as XML.
|
|
237
|
-
This class is responsible for finding <tool> blocks and delegating the
|
|
238
|
-
parsing of their arguments to the specialized _XmlArgumentsParser.
|
|
239
|
-
"""
|
|
240
|
-
|
|
241
|
-
def get_name(self) -> str:
|
|
242
|
-
return "default_xml_tool_usage_parser"
|
|
243
|
-
|
|
244
|
-
def parse(self, response: 'CompleteResponse') -> List[ToolInvocation]:
|
|
245
|
-
text = response.content
|
|
246
|
-
invocations: List[ToolInvocation] = []
|
|
247
|
-
i = 0
|
|
248
|
-
|
|
249
|
-
while i < len(text):
|
|
250
|
-
try:
|
|
251
|
-
i = text.index('<tool', i)
|
|
252
|
-
except ValueError:
|
|
253
|
-
break
|
|
254
|
-
|
|
255
|
-
open_tag_end = text.find('>', i)
|
|
256
|
-
if open_tag_end == -1: break
|
|
257
|
-
|
|
258
|
-
open_tag_content = text[i:open_tag_end+1]
|
|
259
|
-
name_match = re.search(r'name="([^"]+)"', open_tag_content)
|
|
260
|
-
if not name_match:
|
|
261
|
-
i = open_tag_end + 1
|
|
262
|
-
continue
|
|
263
|
-
|
|
264
|
-
tool_name = name_match.group(1)
|
|
265
|
-
logger.debug(f"--- Found tool '{tool_name}' at index {i} ---")
|
|
266
|
-
|
|
267
|
-
cursor = open_tag_end + 1
|
|
268
|
-
nesting_level = 1
|
|
269
|
-
content_end = -1
|
|
270
|
-
|
|
271
|
-
while cursor < len(text):
|
|
272
|
-
next_open = text.find('<tool', cursor)
|
|
273
|
-
next_close = text.find('</tool>', cursor)
|
|
274
|
-
|
|
275
|
-
if next_close == -1: break
|
|
276
|
-
|
|
277
|
-
if next_open != -1 and next_open < next_close:
|
|
278
|
-
nesting_level += 1
|
|
279
|
-
end_of_nested_open = text.find('>', next_open)
|
|
280
|
-
if end_of_nested_open == -1: break
|
|
281
|
-
cursor = end_of_nested_open + 1
|
|
282
|
-
else:
|
|
283
|
-
nesting_level -= 1
|
|
284
|
-
if nesting_level == 0:
|
|
285
|
-
content_end = next_close
|
|
286
|
-
break
|
|
287
|
-
cursor = next_close + len('</tool>')
|
|
288
|
-
|
|
289
|
-
if content_end == -1:
|
|
290
|
-
logger.warning(f"Malformed XML for tool '{tool_name}': could not find matching </tool> tag.")
|
|
291
|
-
i = open_tag_end + 1
|
|
292
|
-
continue
|
|
293
|
-
|
|
294
|
-
tool_content = text[open_tag_end+1:content_end]
|
|
295
|
-
args_match = re.search(r'<arguments>(.*)</arguments>', tool_content, re.DOTALL)
|
|
296
|
-
|
|
297
|
-
arguments = {}
|
|
298
|
-
if args_match:
|
|
299
|
-
arguments_xml = args_match.group(1)
|
|
300
|
-
try:
|
|
301
|
-
# Delegate parsing to the specialized class
|
|
302
|
-
arguments = self._parse_arguments(arguments_xml)
|
|
303
|
-
except Exception as e:
|
|
304
|
-
logger.error(f"Arguments parser failed for tool '{tool_name}': {e}", exc_info=True)
|
|
305
|
-
|
|
306
|
-
invocations.append(ToolInvocation(name=tool_name, arguments=arguments))
|
|
307
|
-
i = content_end + len('</tool>')
|
|
308
|
-
|
|
309
|
-
return invocations
|
|
310
|
-
|
|
311
|
-
def _parse_arguments(self, xml_string: str) -> Dict[str, Any]:
|
|
312
|
-
"""
|
|
313
|
-
Delegates parsing of an arguments XML string to the dedicated parser class.
|
|
314
|
-
"""
|
|
315
|
-
parser = _XmlArgumentsParser(xml_string)
|
|
316
|
-
return parser.parse()
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/tools/usage/parsers/exceptions.py
|
|
2
|
-
"""
|
|
3
|
-
Custom exceptions for the tool usage parsing module.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
class ToolUsageParseException(Exception):
|
|
7
|
-
"""
|
|
8
|
-
Raised when a tool usage parser fails to parse an LLM response due to
|
|
9
|
-
malformed content or other parsing errors.
|
|
10
|
-
"""
|
|
11
|
-
def __init__(self, message: str, original_exception: Exception = None):
|
|
12
|
-
super().__init__(message)
|
|
13
|
-
self.original_exception = original_exception
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py
|
|
2
|
-
import json
|
|
3
|
-
import logging
|
|
4
|
-
from typing import TYPE_CHECKING, List, Dict
|
|
5
|
-
|
|
6
|
-
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
7
|
-
from .base_parser import BaseToolUsageParser
|
|
8
|
-
from .exceptions import ToolUsageParseException
|
|
9
|
-
from ._json_extractor import _find_json_blobs
|
|
10
|
-
from ._string_decoders import decode_html_entities
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from autobyteus.llm.utils.response_types import CompleteResponse
|
|
14
|
-
|
|
15
|
-
logger = logging.getLogger(__name__)
|
|
16
|
-
|
|
17
|
-
class GeminiJsonToolUsageParser(BaseToolUsageParser):
|
|
18
|
-
"""
|
|
19
|
-
Parses LLM responses for tool usage commands formatted in the Google Gemini style.
|
|
20
|
-
It expects a JSON object with "name" and "args" keys. It robustly extracts
|
|
21
|
-
all potential JSON objects from the response and can handle both a single
|
|
22
|
-
tool call object or a list of tool call objects.
|
|
23
|
-
"""
|
|
24
|
-
def get_name(self) -> str:
|
|
25
|
-
return "gemini_json_tool_usage_parser"
|
|
26
|
-
|
|
27
|
-
def parse(self, response: 'CompleteResponse') -> List[ToolInvocation]:
|
|
28
|
-
response_text = response.content
|
|
29
|
-
json_blobs = _find_json_blobs(response_text)
|
|
30
|
-
if not json_blobs:
|
|
31
|
-
return []
|
|
32
|
-
|
|
33
|
-
invocations: List[ToolInvocation] = []
|
|
34
|
-
for blob in json_blobs:
|
|
35
|
-
try:
|
|
36
|
-
data = json.loads(blob)
|
|
37
|
-
|
|
38
|
-
tool_call_list: List[Dict] = []
|
|
39
|
-
if isinstance(data, list):
|
|
40
|
-
# The blob is a list of tool calls, e.g., [{"name": ..., "args": ...}]
|
|
41
|
-
tool_call_list = data
|
|
42
|
-
elif isinstance(data, dict) and "name" in data and "args" in data:
|
|
43
|
-
# The blob is a single tool call object, e.g., {"name": ..., "args": ...}
|
|
44
|
-
tool_call_list = [data]
|
|
45
|
-
else:
|
|
46
|
-
# Not a recognized format, skip this blob.
|
|
47
|
-
logger.debug(f"JSON blob is not in a recognized Gemini tool call format: {blob[:200]}")
|
|
48
|
-
continue
|
|
49
|
-
|
|
50
|
-
for call_data in tool_call_list:
|
|
51
|
-
if not (isinstance(call_data, dict) and "name" in call_data and "args" in call_data):
|
|
52
|
-
logger.debug(f"Skipping malformed item in Gemini tool call list: {call_data}")
|
|
53
|
-
continue
|
|
54
|
-
|
|
55
|
-
tool_name = call_data.get("name")
|
|
56
|
-
arguments = call_data.get("args")
|
|
57
|
-
|
|
58
|
-
if tool_name and isinstance(tool_name, str) and isinstance(arguments, dict):
|
|
59
|
-
decoded_tool_name = decode_html_entities(tool_name)
|
|
60
|
-
decoded_arguments = decode_html_entities(arguments)
|
|
61
|
-
# Pass id=None to trigger deterministic ID generation in ToolInvocation
|
|
62
|
-
tool_invocation = ToolInvocation(name=decoded_tool_name, arguments=decoded_arguments)
|
|
63
|
-
invocations.append(tool_invocation)
|
|
64
|
-
logger.info(f"Successfully parsed Gemini JSON tool invocation for '{tool_name}'.")
|
|
65
|
-
else:
|
|
66
|
-
logger.debug(f"Skipping malformed Gemini tool call data: {call_data}")
|
|
67
|
-
|
|
68
|
-
except json.JSONDecodeError:
|
|
69
|
-
logger.debug(f"Could not parse extracted text as JSON in {self.get_name()}. Blob: {blob[:200]}")
|
|
70
|
-
# Not a tool call, ignore.
|
|
71
|
-
continue
|
|
72
|
-
except Exception as e:
|
|
73
|
-
error_msg = f"Unexpected error while parsing JSON blob in {self.get_name()}: {e}. Blob: {blob[:200]}"
|
|
74
|
-
logger.error(error_msg, exc_info=True)
|
|
75
|
-
raise ToolUsageParseException(error_msg, original_exception=e)
|
|
76
|
-
|
|
77
|
-
return invocations
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py
|
|
2
|
-
import json
|
|
3
|
-
import logging
|
|
4
|
-
from typing import TYPE_CHECKING, List, Optional, Any, Dict
|
|
5
|
-
|
|
6
|
-
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
7
|
-
from .base_parser import BaseToolUsageParser
|
|
8
|
-
from .exceptions import ToolUsageParseException
|
|
9
|
-
from ._json_extractor import _find_json_blobs
|
|
10
|
-
from ._string_decoders import decode_html_entities
|
|
11
|
-
|
|
12
|
-
if TYPE_CHECKING:
|
|
13
|
-
from autobyteus.llm.utils.response_types import CompleteResponse
|
|
14
|
-
|
|
15
|
-
logger = logging.getLogger(__name__)
|
|
16
|
-
|
|
17
|
-
class OpenAiJsonToolUsageParser(BaseToolUsageParser):
|
|
18
|
-
"""
|
|
19
|
-
Parses LLM responses for tool usage commands formatted in various JSON
|
|
20
|
-
styles commonly produced by OpenAI and similar models.
|
|
21
|
-
|
|
22
|
-
This parser is highly flexible and robustly handles multiple formats:
|
|
23
|
-
- A root object with a "tool_calls" or "tools" key containing a list of tool calls.
|
|
24
|
-
- A root object with a single "tool" key.
|
|
25
|
-
- A root object that is itself a single tool call.
|
|
26
|
-
- A raw list of tool calls.
|
|
27
|
-
- Tool call arguments can be either a JSON object or a stringified JSON.
|
|
28
|
-
"""
|
|
29
|
-
def get_name(self) -> str:
|
|
30
|
-
return "openai_json_tool_usage_parser"
|
|
31
|
-
|
|
32
|
-
def parse(self, response: 'CompleteResponse') -> List[ToolInvocation]:
|
|
33
|
-
response_text = response.content
|
|
34
|
-
invocations: List[ToolInvocation] = []
|
|
35
|
-
|
|
36
|
-
# Use a robust method to find all potential JSON blobs in the text
|
|
37
|
-
json_blobs = _find_json_blobs(response_text)
|
|
38
|
-
if not json_blobs:
|
|
39
|
-
logger.debug("No valid JSON object could be extracted from the response content.")
|
|
40
|
-
return invocations
|
|
41
|
-
|
|
42
|
-
for blob in json_blobs:
|
|
43
|
-
try:
|
|
44
|
-
data = json.loads(blob)
|
|
45
|
-
|
|
46
|
-
# Determine the structure of the JSON data
|
|
47
|
-
tool_calls_data: List[Dict[str, Any]] = []
|
|
48
|
-
if isinstance(data, list):
|
|
49
|
-
# Format: [{"function":...}, {"function":...}]
|
|
50
|
-
tool_calls_data = data
|
|
51
|
-
elif isinstance(data, dict):
|
|
52
|
-
# Format: {"tool_calls": [...]} or {"tools": [...]}
|
|
53
|
-
if "tool_calls" in data and isinstance(data["tool_calls"], list):
|
|
54
|
-
tool_calls_data = data["tool_calls"]
|
|
55
|
-
elif "tools" in data and isinstance(data["tools"], list):
|
|
56
|
-
tool_calls_data = data["tools"]
|
|
57
|
-
# Format: {"tool": {...}}
|
|
58
|
-
elif "tool" in data and isinstance(data["tool"], dict):
|
|
59
|
-
tool_calls_data = [data["tool"]]
|
|
60
|
-
# Format: {"function": ...}
|
|
61
|
-
else:
|
|
62
|
-
tool_calls_data = [data]
|
|
63
|
-
|
|
64
|
-
if not tool_calls_data:
|
|
65
|
-
logger.debug(f"JSON response does not match any expected tool call format. Content: {blob[:200]}")
|
|
66
|
-
continue
|
|
67
|
-
|
|
68
|
-
for call_data in tool_calls_data:
|
|
69
|
-
invocation = self._parse_tool_call_object(call_data)
|
|
70
|
-
if invocation:
|
|
71
|
-
invocations.append(invocation)
|
|
72
|
-
|
|
73
|
-
except json.JSONDecodeError:
|
|
74
|
-
# This can happen if a blob is not a tool call (e.g., just example JSON).
|
|
75
|
-
# We can safely ignore these.
|
|
76
|
-
logger.debug(f"Could not parse extracted text as JSON in {self.get_name()}. Blob: {blob[:200]}")
|
|
77
|
-
continue
|
|
78
|
-
except Exception as e:
|
|
79
|
-
# If we're here, it's likely a valid JSON but with unexpected structure.
|
|
80
|
-
# It's safer to raise this for upstream handling.
|
|
81
|
-
error_msg = f"Unexpected error while parsing JSON blob: {e}. Blob: {blob[:200]}"
|
|
82
|
-
logger.error(error_msg, exc_info=True)
|
|
83
|
-
raise ToolUsageParseException(error_msg, original_exception=e)
|
|
84
|
-
|
|
85
|
-
return invocations
|
|
86
|
-
|
|
87
|
-
def _parse_tool_call_object(self, call_data: Dict[str, Any]) -> Optional[ToolInvocation]:
|
|
88
|
-
"""
|
|
89
|
-
Parses a single tool call object, which can have various structures.
|
|
90
|
-
- {"function": {"name": str, "arguments": str_json_or_dict}}
|
|
91
|
-
- {"name": str, "arguments": dict}
|
|
92
|
-
"""
|
|
93
|
-
if not isinstance(call_data, dict):
|
|
94
|
-
logger.debug(f"Skipping non-dictionary item in tool call list: {call_data}")
|
|
95
|
-
return None
|
|
96
|
-
|
|
97
|
-
function_data: Optional[Dict] = call_data.get("function")
|
|
98
|
-
if isinstance(function_data, dict):
|
|
99
|
-
# Standard OpenAI format: {"function": {"name": ..., "arguments": ...}}
|
|
100
|
-
tool_name = function_data.get("name")
|
|
101
|
-
arguments_raw = function_data.get("arguments")
|
|
102
|
-
else:
|
|
103
|
-
# Handle flattened format: {"name": ..., "arguments": ...}
|
|
104
|
-
tool_name = call_data.get("name")
|
|
105
|
-
arguments_raw = call_data.get("arguments")
|
|
106
|
-
|
|
107
|
-
if not tool_name or not isinstance(tool_name, str):
|
|
108
|
-
logger.debug(f"Skipping malformed tool call (missing or invalid 'name'): {call_data}")
|
|
109
|
-
return None
|
|
110
|
-
|
|
111
|
-
arguments: Dict[str, Any]
|
|
112
|
-
if arguments_raw is None:
|
|
113
|
-
arguments = {}
|
|
114
|
-
elif isinstance(arguments_raw, dict):
|
|
115
|
-
# Arguments are already a dictionary
|
|
116
|
-
arguments = arguments_raw
|
|
117
|
-
elif isinstance(arguments_raw, str):
|
|
118
|
-
# Arguments are a stringified JSON
|
|
119
|
-
arg_string = arguments_raw.strip()
|
|
120
|
-
if not arg_string:
|
|
121
|
-
arguments = {}
|
|
122
|
-
else:
|
|
123
|
-
try:
|
|
124
|
-
parsed_args = json.loads(arg_string)
|
|
125
|
-
if not isinstance(parsed_args, dict):
|
|
126
|
-
logger.error(f"Parsed 'arguments' string for tool '{tool_name}' must be a dictionary, but got {type(parsed_args)}.")
|
|
127
|
-
return None
|
|
128
|
-
arguments = parsed_args
|
|
129
|
-
except json.JSONDecodeError as e:
|
|
130
|
-
# If it's a string but not valid JSON, it's a hard error.
|
|
131
|
-
raise ToolUsageParseException(
|
|
132
|
-
f"Failed to parse 'arguments' string for tool '{tool_name}': {arguments_raw}",
|
|
133
|
-
original_exception=e
|
|
134
|
-
)
|
|
135
|
-
else:
|
|
136
|
-
# Any other type for arguments is invalid
|
|
137
|
-
logger.error(f"Skipping tool call with invalid 'arguments' type. Expected dict or string, got {type(arguments_raw)}: {call_data}")
|
|
138
|
-
return None
|
|
139
|
-
|
|
140
|
-
try:
|
|
141
|
-
# The ToolInvocation constructor will generate a deterministic ID if 'id' is None.
|
|
142
|
-
decoded_tool_name = decode_html_entities(tool_name)
|
|
143
|
-
decoded_arguments = decode_html_entities(arguments)
|
|
144
|
-
tool_invocation = ToolInvocation(name=decoded_tool_name, arguments=decoded_arguments, id=None)
|
|
145
|
-
logger.info(f"Successfully parsed OpenAI-style JSON tool invocation for '{tool_name}'.")
|
|
146
|
-
return tool_invocation
|
|
147
|
-
except Exception as e:
|
|
148
|
-
logger.error(f"Unexpected error creating ToolInvocation for tool '{tool_name}': {e}", exc_info=True)
|
|
149
|
-
return None
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py
|
|
2
|
-
import logging
|
|
3
|
-
from typing import TYPE_CHECKING, List
|
|
4
|
-
|
|
5
|
-
from .exceptions import ToolUsageParseException
|
|
6
|
-
|
|
7
|
-
# The import of ToolUsageParserRegistry is deferred to break the circular dependency.
|
|
8
|
-
# It is imported at the top level only for static type analysis.
|
|
9
|
-
if TYPE_CHECKING:
|
|
10
|
-
from autobyteus.agent.context import AgentContext
|
|
11
|
-
from autobyteus.llm.utils.response_types import CompleteResponse
|
|
12
|
-
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
13
|
-
from autobyteus.tools.usage.registries.tool_usage_parser_registry import ToolUsageParserRegistry
|
|
14
|
-
|
|
15
|
-
logger = logging.getLogger(__name__)
|
|
16
|
-
|
|
17
|
-
class ProviderAwareToolUsageParser:
|
|
18
|
-
"""
|
|
19
|
-
A high-level orchestrator that selects and uses the correct tool usage parser
|
|
20
|
-
based on the agent's LLM provider by consulting the central ToolUsageParserRegistry.
|
|
21
|
-
"""
|
|
22
|
-
def __init__(self):
|
|
23
|
-
# Local import to break the circular dependency at module load time.
|
|
24
|
-
from autobyteus.tools.usage.registries.tool_usage_parser_registry import ToolUsageParserRegistry
|
|
25
|
-
self._parser_registry: 'ToolUsageParserRegistry' = ToolUsageParserRegistry()
|
|
26
|
-
logger.debug("ProviderAwareToolUsageParser initialized.")
|
|
27
|
-
|
|
28
|
-
def parse(self, response: 'CompleteResponse', context: 'AgentContext') -> List['ToolInvocation']:
|
|
29
|
-
"""
|
|
30
|
-
Selects the correct underlying parser from the registry, parses the response,
|
|
31
|
-
and returns a list of tool invocations.
|
|
32
|
-
|
|
33
|
-
Args:
|
|
34
|
-
response: The CompleteResponse object from the LLM.
|
|
35
|
-
context: The agent's context, used to determine configuration.
|
|
36
|
-
|
|
37
|
-
Returns:
|
|
38
|
-
A list of ToolInvocation objects. Returns an empty list if no
|
|
39
|
-
valid tool calls are found.
|
|
40
|
-
"""
|
|
41
|
-
llm_provider = None
|
|
42
|
-
if context.llm_instance and context.llm_instance.model:
|
|
43
|
-
llm_provider = context.llm_instance.model.provider
|
|
44
|
-
else:
|
|
45
|
-
logger.warning(f"Agent '{context.agent_id}': LLM instance or model not available. Cannot determine provider for tool response parsing.")
|
|
46
|
-
|
|
47
|
-
# Retrieve the override flag from the agent's configuration.
|
|
48
|
-
use_xml_tool_format = context.config.use_xml_tool_format
|
|
49
|
-
|
|
50
|
-
# Get the correct parser from the registry, passing the override flag.
|
|
51
|
-
parser = self._parser_registry.get_parser(llm_provider, use_xml_tool_format=use_xml_tool_format)
|
|
52
|
-
|
|
53
|
-
logger.debug(f"ProviderAwareToolUsageParser selected delegate parser '{parser.get_name()}' for LLM provider '{llm_provider.name if llm_provider else 'Unknown'}'.")
|
|
54
|
-
|
|
55
|
-
try:
|
|
56
|
-
return parser.parse(response)
|
|
57
|
-
except ToolUsageParseException:
|
|
58
|
-
# Propagate the exception upwards to be handled by the caller.
|
|
59
|
-
raise
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# file: autobyteus/autobyteus/tools/usage/registries/tool_usage_parser_registry.py
|
|
2
|
-
import logging
|
|
3
|
-
from typing import Dict, Optional
|
|
4
|
-
|
|
5
|
-
from autobyteus.llm.providers import LLMProvider
|
|
6
|
-
from autobyteus.utils.singleton import SingletonMeta
|
|
7
|
-
from autobyteus.tools.usage.parsers import (
|
|
8
|
-
BaseToolUsageParser,
|
|
9
|
-
DefaultJsonToolUsageParser,
|
|
10
|
-
OpenAiJsonToolUsageParser,
|
|
11
|
-
GeminiJsonToolUsageParser,
|
|
12
|
-
DefaultXmlToolUsageParser
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
logger = logging.getLogger(__name__)
|
|
16
|
-
|
|
17
|
-
class ToolUsageParserRegistry(metaclass=SingletonMeta):
|
|
18
|
-
"""
|
|
19
|
-
A consolidated registry that maps an LLMProvider directly to its required
|
|
20
|
-
tool usage parser, encapsulating the logic of which provider uses which format.
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
def __init__(self):
|
|
24
|
-
self._parsers: Dict[LLMProvider, BaseToolUsageParser] = {
|
|
25
|
-
# JSON-based providers
|
|
26
|
-
LLMProvider.OPENAI: OpenAiJsonToolUsageParser(),
|
|
27
|
-
LLMProvider.MISTRAL: OpenAiJsonToolUsageParser(),
|
|
28
|
-
LLMProvider.DEEPSEEK: OpenAiJsonToolUsageParser(),
|
|
29
|
-
LLMProvider.GROK: OpenAiJsonToolUsageParser(),
|
|
30
|
-
LLMProvider.GEMINI: GeminiJsonToolUsageParser(),
|
|
31
|
-
|
|
32
|
-
# XML-based providers
|
|
33
|
-
LLMProvider.ANTHROPIC: DefaultXmlToolUsageParser(),
|
|
34
|
-
}
|
|
35
|
-
# A default parser for any provider not explicitly listed (defaults to JSON)
|
|
36
|
-
self._default_parser = DefaultJsonToolUsageParser()
|
|
37
|
-
# A specific parser for the XML override
|
|
38
|
-
self._xml_override_parser = DefaultXmlToolUsageParser()
|
|
39
|
-
logger.info("ToolUsageParserRegistry initialized with direct provider-to-parser mappings.")
|
|
40
|
-
|
|
41
|
-
def get_parser(self, provider: Optional[LLMProvider], use_xml_tool_format: bool = False) -> BaseToolUsageParser:
|
|
42
|
-
"""
|
|
43
|
-
Retrieves the appropriate tool usage parser for a given provider, honoring the XML override.
|
|
44
|
-
|
|
45
|
-
Args:
|
|
46
|
-
provider: The LLMProvider enum member.
|
|
47
|
-
use_xml_tool_format: If True, forces the use of the XML parser.
|
|
48
|
-
|
|
49
|
-
Returns:
|
|
50
|
-
The corresponding BaseToolUsageParser instance.
|
|
51
|
-
"""
|
|
52
|
-
if use_xml_tool_format:
|
|
53
|
-
logger.debug("XML tool format is forced by configuration. Returning XML parser.")
|
|
54
|
-
return self._xml_override_parser
|
|
55
|
-
|
|
56
|
-
if provider and provider in self._parsers:
|
|
57
|
-
parser = self._parsers[provider]
|
|
58
|
-
logger.debug(f"Found specific tool usage parser for provider {provider.name}: {parser.get_name()}")
|
|
59
|
-
return parser
|
|
60
|
-
|
|
61
|
-
logger.debug(f"No specific tool usage parser for provider {provider.name if provider else 'Unknown'}. Returning default parser.")
|
|
62
|
-
return self._default_parser
|