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
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent/streaming/api_tool_call_streaming_response_handler.py
|
|
2
|
+
"""
|
|
3
|
+
ApiToolCallStreamingResponseHandler: Handler for API-provided tool calls.
|
|
4
|
+
|
|
5
|
+
This handler processes SDK-provided tool calls from providers like OpenAI,
|
|
6
|
+
Anthropic, and Gemini. It emits SegmentEvents and uses an internal
|
|
7
|
+
ToolInvocationAdapter to create ToolInvocations.
|
|
8
|
+
"""
|
|
9
|
+
import json
|
|
10
|
+
import uuid
|
|
11
|
+
import logging
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from typing import Optional, List, Dict, Callable
|
|
14
|
+
|
|
15
|
+
from .streaming_response_handler import StreamingResponseHandler
|
|
16
|
+
from ..segments.segment_events import SegmentEvent, SegmentType, SegmentEventType
|
|
17
|
+
from ..adapters.invocation_adapter import ToolInvocationAdapter
|
|
18
|
+
from ..api_tool_call.file_content_streamer import WriteFileContentStreamer, PatchFileContentStreamer
|
|
19
|
+
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
20
|
+
from autobyteus.llm.utils.response_types import ChunkResponse
|
|
21
|
+
|
|
22
|
+
logger = logging.getLogger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class ToolCallState:
|
|
27
|
+
"""Tracks the state of an in-progress tool call."""
|
|
28
|
+
segment_id: str
|
|
29
|
+
name: str
|
|
30
|
+
accumulated_args: str = ""
|
|
31
|
+
segment_type: SegmentType = SegmentType.TOOL_CALL
|
|
32
|
+
streamer: Optional[object] = None
|
|
33
|
+
path: Optional[str] = None
|
|
34
|
+
segment_started: bool = False
|
|
35
|
+
pending_content: str = ""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class ApiToolCallStreamingResponseHandler(StreamingResponseHandler):
|
|
39
|
+
"""
|
|
40
|
+
Handler for API-provided tool calls (OpenAI, Anthropic, Gemini native tool calling).
|
|
41
|
+
|
|
42
|
+
Responsibilities:
|
|
43
|
+
1. Emit TEXT segments for text content
|
|
44
|
+
2. Emit TOOL_CALL segments for SDK-provided tool calls
|
|
45
|
+
3. Use internal ToolInvocationAdapter to create ToolInvocations
|
|
46
|
+
|
|
47
|
+
Key Design:
|
|
48
|
+
- Handler emits SegmentEvents
|
|
49
|
+
- Internal adapter processes events to create ToolInvocations
|
|
50
|
+
- get_all_invocations() returns adapter results (consistent interface)
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def __init__(
|
|
54
|
+
self,
|
|
55
|
+
on_segment_event: Optional[Callable[[SegmentEvent], None]] = None,
|
|
56
|
+
on_tool_invocation: Optional[Callable[[ToolInvocation], None]] = None,
|
|
57
|
+
segment_id_prefix: str = "",
|
|
58
|
+
):
|
|
59
|
+
self._on_segment_event = on_segment_event
|
|
60
|
+
self._on_tool_invocation = on_tool_invocation
|
|
61
|
+
self._segment_id_prefix = segment_id_prefix
|
|
62
|
+
|
|
63
|
+
# Internal adapter for creating invocations from events
|
|
64
|
+
self._adapter = ToolInvocationAdapter()
|
|
65
|
+
|
|
66
|
+
# State tracking
|
|
67
|
+
self._text_segment_id: Optional[str] = None
|
|
68
|
+
self._active_tools: Dict[int, ToolCallState] = {} # index -> state
|
|
69
|
+
self._all_events: List[SegmentEvent] = []
|
|
70
|
+
self._all_invocations: List[ToolInvocation] = []
|
|
71
|
+
self._is_finalized = False
|
|
72
|
+
|
|
73
|
+
def _generate_id(self) -> str:
|
|
74
|
+
return f"{self._segment_id_prefix}{uuid.uuid4().hex}"
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def _resolve_segment_type(tool_name: str):
|
|
78
|
+
if tool_name == "write_file":
|
|
79
|
+
return SegmentType.WRITE_FILE, WriteFileContentStreamer()
|
|
80
|
+
if tool_name == "patch_file":
|
|
81
|
+
return SegmentType.PATCH_FILE, PatchFileContentStreamer()
|
|
82
|
+
return SegmentType.TOOL_CALL, None
|
|
83
|
+
|
|
84
|
+
def _emit(self, event: SegmentEvent) -> None:
|
|
85
|
+
"""Emit event and process through internal adapter."""
|
|
86
|
+
self._all_events.append(event)
|
|
87
|
+
|
|
88
|
+
# Notify callback
|
|
89
|
+
if self._on_segment_event:
|
|
90
|
+
try:
|
|
91
|
+
self._on_segment_event(event)
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"Error in on_segment_event callback: {e}")
|
|
94
|
+
|
|
95
|
+
# Process through internal adapter
|
|
96
|
+
invocation = self._adapter.process_event(event)
|
|
97
|
+
if invocation:
|
|
98
|
+
self._all_invocations.append(invocation)
|
|
99
|
+
if self._on_tool_invocation:
|
|
100
|
+
try:
|
|
101
|
+
self._on_tool_invocation(invocation)
|
|
102
|
+
except Exception as e:
|
|
103
|
+
logger.error(f"Error in on_tool_invocation callback: {e}")
|
|
104
|
+
|
|
105
|
+
def feed(self, chunk: ChunkResponse) -> List[SegmentEvent]:
|
|
106
|
+
if self._is_finalized:
|
|
107
|
+
raise RuntimeError("Handler has been finalized.")
|
|
108
|
+
|
|
109
|
+
events = []
|
|
110
|
+
|
|
111
|
+
# 1. Handle text content → TEXT segment
|
|
112
|
+
if chunk.content:
|
|
113
|
+
if self._text_segment_id is None:
|
|
114
|
+
self._text_segment_id = self._generate_id()
|
|
115
|
+
start_event = SegmentEvent.start(
|
|
116
|
+
segment_id=self._text_segment_id,
|
|
117
|
+
segment_type=SegmentType.TEXT
|
|
118
|
+
)
|
|
119
|
+
self._emit(start_event)
|
|
120
|
+
events.append(start_event)
|
|
121
|
+
|
|
122
|
+
content_event = SegmentEvent.content(
|
|
123
|
+
segment_id=self._text_segment_id,
|
|
124
|
+
delta=chunk.content
|
|
125
|
+
)
|
|
126
|
+
self._emit(content_event)
|
|
127
|
+
events.append(content_event)
|
|
128
|
+
|
|
129
|
+
# 2. Handle tool calls from SDK
|
|
130
|
+
if chunk.tool_calls:
|
|
131
|
+
for delta in chunk.tool_calls:
|
|
132
|
+
if delta.index not in self._active_tools:
|
|
133
|
+
# New tool call - emit SEGMENT_START
|
|
134
|
+
seg_id = delta.call_id or self._generate_id()
|
|
135
|
+
tool_name = delta.name or ""
|
|
136
|
+
segment_type, streamer = self._resolve_segment_type(tool_name)
|
|
137
|
+
self._active_tools[delta.index] = ToolCallState(
|
|
138
|
+
segment_id=seg_id,
|
|
139
|
+
name=tool_name,
|
|
140
|
+
accumulated_args="",
|
|
141
|
+
segment_type=segment_type,
|
|
142
|
+
streamer=streamer,
|
|
143
|
+
)
|
|
144
|
+
if segment_type == SegmentType.TOOL_CALL:
|
|
145
|
+
start_event = SegmentEvent.start(
|
|
146
|
+
segment_id=seg_id,
|
|
147
|
+
segment_type=segment_type,
|
|
148
|
+
tool_name=tool_name,
|
|
149
|
+
)
|
|
150
|
+
self._active_tools[delta.index].segment_started = True
|
|
151
|
+
self._emit(start_event)
|
|
152
|
+
events.append(start_event)
|
|
153
|
+
|
|
154
|
+
# Accumulate arguments and emit content delta (for UI streaming)
|
|
155
|
+
if delta.arguments_delta:
|
|
156
|
+
state = self._active_tools[delta.index]
|
|
157
|
+
state.accumulated_args += delta.arguments_delta
|
|
158
|
+
|
|
159
|
+
if state.segment_type == SegmentType.TOOL_CALL:
|
|
160
|
+
if not state.segment_started:
|
|
161
|
+
start_event = SegmentEvent.start(
|
|
162
|
+
segment_id=state.segment_id,
|
|
163
|
+
segment_type=state.segment_type,
|
|
164
|
+
tool_name=state.name,
|
|
165
|
+
)
|
|
166
|
+
state.segment_started = True
|
|
167
|
+
self._emit(start_event)
|
|
168
|
+
events.append(start_event)
|
|
169
|
+
content_event = SegmentEvent.content(
|
|
170
|
+
segment_id=state.segment_id,
|
|
171
|
+
delta=delta.arguments_delta,
|
|
172
|
+
)
|
|
173
|
+
self._emit(content_event)
|
|
174
|
+
events.append(content_event)
|
|
175
|
+
else:
|
|
176
|
+
update = state.streamer.feed(delta.arguments_delta) if state.streamer else None
|
|
177
|
+
if update and update.path and not state.path:
|
|
178
|
+
state.path = update.path
|
|
179
|
+
if not state.segment_started and state.path:
|
|
180
|
+
start_event = SegmentEvent.start(
|
|
181
|
+
segment_id=state.segment_id,
|
|
182
|
+
segment_type=state.segment_type,
|
|
183
|
+
tool_name=state.name,
|
|
184
|
+
path=state.path,
|
|
185
|
+
)
|
|
186
|
+
state.segment_started = True
|
|
187
|
+
self._emit(start_event)
|
|
188
|
+
events.append(start_event)
|
|
189
|
+
if state.pending_content:
|
|
190
|
+
content_event = SegmentEvent.content(
|
|
191
|
+
segment_id=state.segment_id,
|
|
192
|
+
delta=state.pending_content,
|
|
193
|
+
)
|
|
194
|
+
self._emit(content_event)
|
|
195
|
+
events.append(content_event)
|
|
196
|
+
state.pending_content = ""
|
|
197
|
+
if update and update.content_delta:
|
|
198
|
+
if state.segment_started:
|
|
199
|
+
content_event = SegmentEvent.content(
|
|
200
|
+
segment_id=state.segment_id,
|
|
201
|
+
delta=update.content_delta,
|
|
202
|
+
)
|
|
203
|
+
self._emit(content_event)
|
|
204
|
+
events.append(content_event)
|
|
205
|
+
else:
|
|
206
|
+
state.pending_content += update.content_delta
|
|
207
|
+
|
|
208
|
+
# Update name if provided later
|
|
209
|
+
if delta.name and not self._active_tools[delta.index].name:
|
|
210
|
+
self._active_tools[delta.index].name = delta.name
|
|
211
|
+
|
|
212
|
+
return events
|
|
213
|
+
|
|
214
|
+
def finalize(self) -> List[SegmentEvent]:
|
|
215
|
+
if self._is_finalized:
|
|
216
|
+
return []
|
|
217
|
+
|
|
218
|
+
self._is_finalized = True
|
|
219
|
+
events = []
|
|
220
|
+
|
|
221
|
+
# Close text segment
|
|
222
|
+
if self._text_segment_id:
|
|
223
|
+
end_event = SegmentEvent.end(segment_id=self._text_segment_id)
|
|
224
|
+
self._emit(end_event)
|
|
225
|
+
events.append(end_event)
|
|
226
|
+
|
|
227
|
+
# Close tool segments with pre-parsed arguments in metadata
|
|
228
|
+
for state in self._active_tools.values():
|
|
229
|
+
if state.segment_type in {SegmentType.WRITE_FILE, SegmentType.PATCH_FILE}:
|
|
230
|
+
if not state.segment_started:
|
|
231
|
+
start_meta = {"tool_name": state.name}
|
|
232
|
+
if state.path:
|
|
233
|
+
start_meta["path"] = state.path
|
|
234
|
+
start_event = SegmentEvent.start(
|
|
235
|
+
segment_id=state.segment_id,
|
|
236
|
+
segment_type=state.segment_type,
|
|
237
|
+
**start_meta,
|
|
238
|
+
)
|
|
239
|
+
state.segment_started = True
|
|
240
|
+
self._emit(start_event)
|
|
241
|
+
events.append(start_event)
|
|
242
|
+
if state.pending_content:
|
|
243
|
+
content_event = SegmentEvent.content(
|
|
244
|
+
segment_id=state.segment_id,
|
|
245
|
+
delta=state.pending_content,
|
|
246
|
+
)
|
|
247
|
+
self._emit(content_event)
|
|
248
|
+
events.append(content_event)
|
|
249
|
+
state.pending_content = ""
|
|
250
|
+
if state.segment_type == SegmentType.TOOL_CALL:
|
|
251
|
+
# Parse accumulated JSON arguments
|
|
252
|
+
try:
|
|
253
|
+
parsed_args = json.loads(state.accumulated_args) if state.accumulated_args else {}
|
|
254
|
+
except json.JSONDecodeError as e:
|
|
255
|
+
logger.error(f"Failed to parse tool arguments for {state.name}: {e}")
|
|
256
|
+
parsed_args = {}
|
|
257
|
+
|
|
258
|
+
# Emit SEGMENT_END with arguments in metadata
|
|
259
|
+
# The internal adapter will use this to create ToolInvocation
|
|
260
|
+
end_event = SegmentEvent(
|
|
261
|
+
event_type=SegmentEventType.END,
|
|
262
|
+
segment_id=state.segment_id,
|
|
263
|
+
payload={
|
|
264
|
+
"metadata": {
|
|
265
|
+
"tool_name": state.name,
|
|
266
|
+
"arguments": parsed_args, # Pre-parsed for adapter
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
else:
|
|
271
|
+
metadata = {}
|
|
272
|
+
if state.path:
|
|
273
|
+
metadata["path"] = state.path
|
|
274
|
+
end_event = SegmentEvent(
|
|
275
|
+
event_type=SegmentEventType.END,
|
|
276
|
+
segment_id=state.segment_id,
|
|
277
|
+
payload={"metadata": metadata} if metadata else {},
|
|
278
|
+
)
|
|
279
|
+
self._emit(end_event)
|
|
280
|
+
events.append(end_event)
|
|
281
|
+
|
|
282
|
+
if self._all_invocations:
|
|
283
|
+
logger.info(
|
|
284
|
+
"ApiToolCallStreamingResponseHandler finalized %d tool invocations.",
|
|
285
|
+
len(self._all_invocations),
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
return events
|
|
289
|
+
|
|
290
|
+
def get_all_events(self) -> List[SegmentEvent]:
|
|
291
|
+
return self._all_events.copy()
|
|
292
|
+
|
|
293
|
+
def get_all_invocations(self) -> List[ToolInvocation]:
|
|
294
|
+
"""Returns invocations created by the internal adapter."""
|
|
295
|
+
return self._all_invocations.copy()
|
|
296
|
+
|
|
297
|
+
def reset(self) -> None:
|
|
298
|
+
self._text_segment_id = None
|
|
299
|
+
self._active_tools.clear()
|
|
300
|
+
self._all_events.clear()
|
|
301
|
+
self._all_invocations.clear()
|
|
302
|
+
self._adapter = ToolInvocationAdapter()
|
|
303
|
+
self._is_finalized = False
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ParsingStreamingResponseHandler: Concrete implementation of StreamingResponseHandler that uses a parser.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Optional, List, Callable, Any, Union
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from .streaming_response_handler import StreamingResponseHandler
|
|
8
|
+
from ..parser.parser_factory import create_streaming_parser, resolve_parser_name
|
|
9
|
+
from ..segments.segment_events import SegmentEvent
|
|
10
|
+
from ..adapters.invocation_adapter import ToolInvocationAdapter
|
|
11
|
+
from ..parser.parser_context import ParserConfig
|
|
12
|
+
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
13
|
+
from autobyteus.llm.utils.response_types import ChunkResponse
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ParsingStreamingResponseHandler(StreamingResponseHandler):
|
|
19
|
+
"""
|
|
20
|
+
Handler that uses a StreamingParser to process the LLM response.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
on_segment_event: Optional[Callable[[SegmentEvent], None]] = None,
|
|
26
|
+
on_tool_invocation: Optional[Callable[[ToolInvocation], None]] = None,
|
|
27
|
+
config: Optional[ParserConfig] = None,
|
|
28
|
+
parser_name: Optional[str] = None,
|
|
29
|
+
):
|
|
30
|
+
"""
|
|
31
|
+
Initialize the parsing response handler.
|
|
32
|
+
"""
|
|
33
|
+
self._parser_name = resolve_parser_name(parser_name)
|
|
34
|
+
self._parser_config = config
|
|
35
|
+
self._parser = create_streaming_parser(
|
|
36
|
+
config=config,
|
|
37
|
+
parser_name=self._parser_name,
|
|
38
|
+
)
|
|
39
|
+
self._adapter = ToolInvocationAdapter(
|
|
40
|
+
json_tool_parser=self._parser.config.json_tool_parser
|
|
41
|
+
)
|
|
42
|
+
self._on_segment_event = on_segment_event
|
|
43
|
+
self._on_tool_invocation = on_tool_invocation
|
|
44
|
+
self._is_finalized = False
|
|
45
|
+
|
|
46
|
+
# Accumulated data
|
|
47
|
+
self._all_events: List[SegmentEvent] = []
|
|
48
|
+
self._all_invocations: List[ToolInvocation] = []
|
|
49
|
+
|
|
50
|
+
def feed(self, chunk: ChunkResponse) -> List[SegmentEvent]:
|
|
51
|
+
if self._is_finalized:
|
|
52
|
+
raise RuntimeError("Handler has been finalized, cannot feed more chunks.")
|
|
53
|
+
|
|
54
|
+
# Extract text content from ChunkResponse (ignore tool_calls - not our concern)
|
|
55
|
+
text_content = chunk.content if isinstance(chunk, ChunkResponse) else chunk
|
|
56
|
+
if not text_content:
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
events = self._parser.feed(text_content)
|
|
60
|
+
self._process_events(events)
|
|
61
|
+
return events
|
|
62
|
+
|
|
63
|
+
def finalize(self) -> List[SegmentEvent]:
|
|
64
|
+
if self._is_finalized:
|
|
65
|
+
return []
|
|
66
|
+
|
|
67
|
+
self._is_finalized = True
|
|
68
|
+
events = self._parser.finalize()
|
|
69
|
+
self._process_events(events)
|
|
70
|
+
return events
|
|
71
|
+
|
|
72
|
+
def _process_events(self, events: List[SegmentEvent]) -> None:
|
|
73
|
+
for event in events:
|
|
74
|
+
self._all_events.append(event)
|
|
75
|
+
|
|
76
|
+
if self._on_segment_event:
|
|
77
|
+
try:
|
|
78
|
+
self._on_segment_event(event)
|
|
79
|
+
except Exception as e:
|
|
80
|
+
logger.error(f"Error in on_segment_event callback: {e}")
|
|
81
|
+
|
|
82
|
+
invocation = self._adapter.process_event(event)
|
|
83
|
+
if invocation:
|
|
84
|
+
self._all_invocations.append(invocation)
|
|
85
|
+
if self._on_tool_invocation:
|
|
86
|
+
try:
|
|
87
|
+
self._on_tool_invocation(invocation)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
logger.error(f"Error in on_tool_invocation callback: {e}")
|
|
90
|
+
|
|
91
|
+
def get_all_events(self) -> List[SegmentEvent]:
|
|
92
|
+
return self._all_events.copy()
|
|
93
|
+
|
|
94
|
+
def get_all_invocations(self) -> List[ToolInvocation]:
|
|
95
|
+
return self._all_invocations.copy()
|
|
96
|
+
|
|
97
|
+
def reset(self) -> None:
|
|
98
|
+
self._parser = create_streaming_parser(
|
|
99
|
+
config=self._parser_config,
|
|
100
|
+
parser_name=self._parser_name,
|
|
101
|
+
)
|
|
102
|
+
self._adapter = ToolInvocationAdapter(
|
|
103
|
+
json_tool_parser=self._parser.config.json_tool_parser
|
|
104
|
+
)
|
|
105
|
+
self._all_events.clear()
|
|
106
|
+
self._all_invocations.clear()
|
|
107
|
+
self._is_finalized = False
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PassThroughStreamingResponseHandler: Implementation of StreamingResponseHandler that bypasses parsing.
|
|
3
|
+
"""
|
|
4
|
+
import uuid
|
|
5
|
+
import logging
|
|
6
|
+
from typing import Optional, List, Callable
|
|
7
|
+
|
|
8
|
+
from .streaming_response_handler import StreamingResponseHandler
|
|
9
|
+
from ..segments.segment_events import SegmentEvent, SegmentType, SegmentEventType
|
|
10
|
+
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
11
|
+
from autobyteus.llm.utils.response_types import ChunkResponse
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PassThroughStreamingResponseHandler(StreamingResponseHandler):
|
|
17
|
+
"""
|
|
18
|
+
Handler that passes raw text chunks directly as segment events without parsing.
|
|
19
|
+
Used when an agent has no tools configured.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(
|
|
23
|
+
self,
|
|
24
|
+
on_segment_event: Optional[Callable[[SegmentEvent], None]] = None,
|
|
25
|
+
on_tool_invocation: Optional[Callable[[ToolInvocation], None]] = None,
|
|
26
|
+
segment_id_prefix: Optional[str] = None,
|
|
27
|
+
):
|
|
28
|
+
"""
|
|
29
|
+
Initialize the pass-through handler.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
on_segment_event: Callback for UI streaming.
|
|
33
|
+
on_tool_invocation: Callback for tools (unused here, kept for compatibility).
|
|
34
|
+
segment_id_prefix: Prefix for the single text segment ID.
|
|
35
|
+
"""
|
|
36
|
+
self._on_segment_event = on_segment_event
|
|
37
|
+
self._segment_id_prefix = segment_id_prefix or f"pt_{uuid.uuid4().hex}:"
|
|
38
|
+
self._segment_id = f"{self._segment_id_prefix}text_0"
|
|
39
|
+
self._is_active = False
|
|
40
|
+
self._is_finalized = False
|
|
41
|
+
self._all_events: List[SegmentEvent] = []
|
|
42
|
+
|
|
43
|
+
def feed(self, chunk: ChunkResponse) -> List[SegmentEvent]:
|
|
44
|
+
if self._is_finalized:
|
|
45
|
+
raise RuntimeError("Handler has been finalized, cannot feed more chunks.")
|
|
46
|
+
|
|
47
|
+
# Extract text content from ChunkResponse
|
|
48
|
+
text_content = chunk.content if isinstance(chunk, ChunkResponse) else chunk
|
|
49
|
+
if not text_content:
|
|
50
|
+
return []
|
|
51
|
+
|
|
52
|
+
events = []
|
|
53
|
+
|
|
54
|
+
# Start segment if not active
|
|
55
|
+
if not self._is_active:
|
|
56
|
+
self._is_active = True
|
|
57
|
+
start_event = SegmentEvent.start(
|
|
58
|
+
segment_id=self._segment_id,
|
|
59
|
+
segment_type=SegmentType.TEXT
|
|
60
|
+
)
|
|
61
|
+
events.append(start_event)
|
|
62
|
+
|
|
63
|
+
# Content event
|
|
64
|
+
content_event = SegmentEvent.content(
|
|
65
|
+
segment_id=self._segment_id,
|
|
66
|
+
delta=text_content
|
|
67
|
+
)
|
|
68
|
+
events.append(content_event)
|
|
69
|
+
|
|
70
|
+
self._process_events(events)
|
|
71
|
+
return events
|
|
72
|
+
|
|
73
|
+
def finalize(self) -> List[SegmentEvent]:
|
|
74
|
+
if self._is_finalized:
|
|
75
|
+
return []
|
|
76
|
+
|
|
77
|
+
self._is_finalized = True
|
|
78
|
+
events = []
|
|
79
|
+
|
|
80
|
+
if self._is_active:
|
|
81
|
+
end_event = SegmentEvent.end(segment_id=self._segment_id)
|
|
82
|
+
events.append(end_event)
|
|
83
|
+
self._is_active = False
|
|
84
|
+
|
|
85
|
+
self._process_events(events)
|
|
86
|
+
return events
|
|
87
|
+
|
|
88
|
+
def _process_events(self, events: List[SegmentEvent]) -> None:
|
|
89
|
+
for event in events:
|
|
90
|
+
self._all_events.append(event)
|
|
91
|
+
if self._on_segment_event:
|
|
92
|
+
try:
|
|
93
|
+
self._on_segment_event(event)
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.error(f"Error in on_segment_event callback: {e}")
|
|
96
|
+
|
|
97
|
+
def get_all_events(self) -> List[SegmentEvent]:
|
|
98
|
+
return self._all_events.copy()
|
|
99
|
+
|
|
100
|
+
def get_all_invocations(self) -> List[ToolInvocation]:
|
|
101
|
+
return []
|
|
102
|
+
|
|
103
|
+
def reset(self) -> None:
|
|
104
|
+
self._segment_id = f"{self._segment_id_prefix}text_{uuid.uuid4().hex}"
|
|
105
|
+
self._is_active = False
|
|
106
|
+
self._is_finalized = False
|
|
107
|
+
self._all_events.clear()
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# file: autobyteus/autobyteus/agent/streaming/handlers/streaming_handler_factory.py
|
|
2
|
+
"""
|
|
3
|
+
Factory for selecting the appropriate StreamingResponseHandler implementation.
|
|
4
|
+
|
|
5
|
+
This factory encapsulates all configuration logic including:
|
|
6
|
+
- Format/mode resolution from environment
|
|
7
|
+
- ParserConfig construction for text parsing modes
|
|
8
|
+
- JSON profile selection for provider-aware parsing
|
|
9
|
+
- Tool schema building for API tool call mode
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
import uuid
|
|
15
|
+
from dataclasses import dataclass, field
|
|
16
|
+
from typing import Optional, Callable, List, Dict
|
|
17
|
+
|
|
18
|
+
from autobyteus.agent.tool_invocation import ToolInvocation
|
|
19
|
+
from autobyteus.llm.providers import LLMProvider
|
|
20
|
+
from autobyteus.utils.tool_call_format import resolve_tool_call_format
|
|
21
|
+
|
|
22
|
+
from .streaming_response_handler import StreamingResponseHandler
|
|
23
|
+
from .parsing_streaming_response_handler import ParsingStreamingResponseHandler
|
|
24
|
+
from .pass_through_streaming_response_handler import PassThroughStreamingResponseHandler
|
|
25
|
+
from .api_tool_call_streaming_response_handler import ApiToolCallStreamingResponseHandler
|
|
26
|
+
from ..parser.parser_context import ParserConfig
|
|
27
|
+
from ..parser.json_parsing_strategies.registry import get_json_tool_parsing_profile
|
|
28
|
+
from ..segments.segment_events import SegmentEvent
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class StreamingHandlerResult:
|
|
35
|
+
"""
|
|
36
|
+
Result of creating a streaming handler.
|
|
37
|
+
|
|
38
|
+
Attributes:
|
|
39
|
+
handler: The configured streaming response handler.
|
|
40
|
+
tool_schemas: Pre-built tool schemas for API mode (None for other modes).
|
|
41
|
+
"""
|
|
42
|
+
handler: StreamingResponseHandler
|
|
43
|
+
tool_schemas: Optional[List[Dict]] = None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class StreamingResponseHandlerFactory:
|
|
47
|
+
"""Factory for building streaming response handlers based on minimal inputs."""
|
|
48
|
+
|
|
49
|
+
@staticmethod
|
|
50
|
+
def create(
|
|
51
|
+
*,
|
|
52
|
+
tool_names: List[str],
|
|
53
|
+
provider: Optional[LLMProvider],
|
|
54
|
+
segment_id_prefix: Optional[str] = None,
|
|
55
|
+
on_segment_event: Optional[Callable[[SegmentEvent], None]] = None,
|
|
56
|
+
on_tool_invocation: Optional[Callable[[ToolInvocation], None]] = None,
|
|
57
|
+
agent_id: Optional[str] = None,
|
|
58
|
+
) -> StreamingHandlerResult:
|
|
59
|
+
"""
|
|
60
|
+
Create a streaming response handler with all necessary configuration.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
tool_names: List of tool names the agent has access to.
|
|
64
|
+
provider: The LLM provider being used (for provider-specific parsing).
|
|
65
|
+
segment_id_prefix: Optional prefix for segment IDs.
|
|
66
|
+
on_segment_event: Callback for UI streaming events.
|
|
67
|
+
on_tool_invocation: Callback when a tool invocation is created.
|
|
68
|
+
agent_id: Agent identifier for logging.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
StreamingHandlerResult containing the handler and optional tool schemas.
|
|
72
|
+
"""
|
|
73
|
+
# Resolve format from environment
|
|
74
|
+
format_override = resolve_tool_call_format()
|
|
75
|
+
parse_tool_calls = bool(tool_names)
|
|
76
|
+
|
|
77
|
+
# Generate segment ID prefix if not provided
|
|
78
|
+
if segment_id_prefix is None:
|
|
79
|
+
segment_id_prefix = f"turn_{uuid.uuid4().hex}:"
|
|
80
|
+
|
|
81
|
+
# No tools → PassThrough handler
|
|
82
|
+
if not parse_tool_calls:
|
|
83
|
+
logger.debug(
|
|
84
|
+
"Agent '%s': No tools enabled - using PassThroughStreamingResponseHandler",
|
|
85
|
+
agent_id or "unknown",
|
|
86
|
+
)
|
|
87
|
+
return StreamingHandlerResult(
|
|
88
|
+
handler=PassThroughStreamingResponseHandler(
|
|
89
|
+
on_segment_event=on_segment_event,
|
|
90
|
+
on_tool_invocation=on_tool_invocation,
|
|
91
|
+
segment_id_prefix=segment_id_prefix,
|
|
92
|
+
),
|
|
93
|
+
tool_schemas=None,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# API tool call mode → ApiToolCall handler + build schemas
|
|
97
|
+
if format_override == "api_tool_call":
|
|
98
|
+
logger.debug(
|
|
99
|
+
"Agent '%s': Using ApiToolCallStreamingResponseHandler",
|
|
100
|
+
agent_id or "unknown",
|
|
101
|
+
)
|
|
102
|
+
# Build tool schemas for API mode
|
|
103
|
+
tool_schemas = StreamingResponseHandlerFactory._build_tool_schemas(
|
|
104
|
+
tool_names=tool_names,
|
|
105
|
+
provider=provider,
|
|
106
|
+
)
|
|
107
|
+
return StreamingHandlerResult(
|
|
108
|
+
handler=ApiToolCallStreamingResponseHandler(
|
|
109
|
+
on_segment_event=on_segment_event,
|
|
110
|
+
on_tool_invocation=on_tool_invocation,
|
|
111
|
+
segment_id_prefix=segment_id_prefix,
|
|
112
|
+
),
|
|
113
|
+
tool_schemas=tool_schemas,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Text parsing mode (XML/JSON/Sentinel) → Parsing handler
|
|
117
|
+
parser_name = StreamingResponseHandlerFactory._resolve_parser_name(
|
|
118
|
+
format_override=format_override,
|
|
119
|
+
provider=provider,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
# Build ParserConfig with provider-aware JSON profile
|
|
123
|
+
json_profile = get_json_tool_parsing_profile(provider)
|
|
124
|
+
parser_config = ParserConfig(
|
|
125
|
+
parse_tool_calls=parse_tool_calls,
|
|
126
|
+
json_tool_patterns=json_profile.signature_patterns,
|
|
127
|
+
json_tool_parser=json_profile.parser,
|
|
128
|
+
segment_id_prefix=segment_id_prefix,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
logger.debug(
|
|
132
|
+
"Agent '%s': Using ParsingStreamingResponseHandler with %s parser",
|
|
133
|
+
agent_id or "unknown",
|
|
134
|
+
parser_name,
|
|
135
|
+
)
|
|
136
|
+
return StreamingHandlerResult(
|
|
137
|
+
handler=ParsingStreamingResponseHandler(
|
|
138
|
+
on_segment_event=on_segment_event,
|
|
139
|
+
on_tool_invocation=on_tool_invocation,
|
|
140
|
+
config=parser_config,
|
|
141
|
+
parser_name=parser_name,
|
|
142
|
+
),
|
|
143
|
+
tool_schemas=None,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
@staticmethod
|
|
147
|
+
def _resolve_parser_name(
|
|
148
|
+
*,
|
|
149
|
+
format_override: Optional[str],
|
|
150
|
+
provider: Optional[LLMProvider],
|
|
151
|
+
) -> str:
|
|
152
|
+
"""Resolve which parser to use based on format and provider."""
|
|
153
|
+
if format_override in {"xml", "json", "sentinel"}:
|
|
154
|
+
return format_override
|
|
155
|
+
# Default: XML for Anthropic, JSON for others
|
|
156
|
+
return "xml" if provider == LLMProvider.ANTHROPIC else "json"
|
|
157
|
+
|
|
158
|
+
@staticmethod
|
|
159
|
+
def _build_tool_schemas(
|
|
160
|
+
tool_names: List[str],
|
|
161
|
+
provider: Optional[LLMProvider],
|
|
162
|
+
) -> Optional[List[Dict]]:
|
|
163
|
+
"""Build tool schemas for API tool call mode."""
|
|
164
|
+
if not tool_names:
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
# Import here to avoid circular dependency
|
|
168
|
+
from autobyteus.tools.usage.tool_schema_provider import ToolSchemaProvider
|
|
169
|
+
|
|
170
|
+
schemas = ToolSchemaProvider().build_schema(tool_names, provider)
|
|
171
|
+
if schemas:
|
|
172
|
+
logger.debug(
|
|
173
|
+
"Built %d tool schemas for API tool calls (provider: %s)",
|
|
174
|
+
len(schemas),
|
|
175
|
+
provider,
|
|
176
|
+
)
|
|
177
|
+
return schemas if schemas else None
|