autobyteus 1.2.1__py3-none-any.whl → 1.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- autobyteus/agent/agent.py +15 -5
- autobyteus/agent/bootstrap_steps/__init__.py +3 -3
- autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +5 -59
- autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +1 -4
- autobyteus/agent/bootstrap_steps/mcp_server_prewarming_step.py +1 -3
- autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +16 -13
- autobyteus/agent/bootstrap_steps/working_context_snapshot_restore_step.py +38 -0
- autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +2 -4
- autobyteus/agent/context/agent_config.py +47 -20
- autobyteus/agent/context/agent_context.py +23 -18
- autobyteus/agent/context/agent_runtime_state.py +21 -19
- autobyteus/agent/events/__init__.py +16 -1
- autobyteus/agent/events/agent_events.py +43 -3
- autobyteus/agent/events/agent_input_event_queue_manager.py +79 -26
- autobyteus/agent/events/event_store.py +57 -0
- autobyteus/agent/events/notifiers.py +69 -59
- autobyteus/agent/events/worker_event_dispatcher.py +21 -64
- autobyteus/agent/factory/agent_factory.py +83 -6
- autobyteus/agent/handlers/__init__.py +2 -0
- autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +51 -34
- autobyteus/agent/handlers/bootstrap_event_handler.py +155 -0
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +10 -0
- autobyteus/agent/handlers/lifecycle_event_logger.py +19 -11
- autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +10 -15
- autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +188 -48
- autobyteus/agent/handlers/tool_execution_approval_event_handler.py +0 -10
- autobyteus/agent/handlers/tool_invocation_request_event_handler.py +53 -48
- autobyteus/agent/handlers/tool_result_event_handler.py +7 -8
- autobyteus/agent/handlers/user_input_message_event_handler.py +10 -3
- autobyteus/agent/input_processor/memory_ingest_input_processor.py +44 -0
- autobyteus/agent/lifecycle/__init__.py +12 -0
- autobyteus/agent/lifecycle/base_processor.py +109 -0
- autobyteus/agent/lifecycle/events.py +35 -0
- autobyteus/agent/lifecycle/processor_definition.py +36 -0
- autobyteus/agent/lifecycle/processor_registry.py +106 -0
- autobyteus/agent/llm_request_assembler.py +98 -0
- autobyteus/agent/llm_response_processor/__init__.py +1 -8
- autobyteus/agent/message/context_file_type.py +1 -1
- autobyteus/agent/runtime/agent_runtime.py +29 -21
- autobyteus/agent/runtime/agent_worker.py +98 -19
- autobyteus/agent/shutdown_steps/__init__.py +2 -0
- autobyteus/agent/shutdown_steps/agent_shutdown_orchestrator.py +2 -0
- autobyteus/agent/shutdown_steps/tool_cleanup_step.py +58 -0
- autobyteus/agent/status/__init__.py +14 -0
- autobyteus/agent/status/manager.py +93 -0
- autobyteus/agent/status/status_deriver.py +96 -0
- autobyteus/agent/{phases/phase_enum.py → status/status_enum.py} +16 -16
- autobyteus/agent/status/status_update_utils.py +73 -0
- autobyteus/agent/streaming/__init__.py +52 -5
- autobyteus/agent/streaming/adapters/__init__.py +18 -0
- autobyteus/agent/streaming/adapters/invocation_adapter.py +184 -0
- autobyteus/agent/streaming/adapters/tool_call_parsing.py +163 -0
- autobyteus/agent/streaming/adapters/tool_syntax_registry.py +67 -0
- autobyteus/agent/streaming/agent_event_stream.py +3 -183
- autobyteus/agent/streaming/api_tool_call/__init__.py +16 -0
- autobyteus/agent/streaming/api_tool_call/file_content_streamer.py +56 -0
- autobyteus/agent/streaming/api_tool_call/json_string_field_extractor.py +175 -0
- autobyteus/agent/streaming/api_tool_call_streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/events/__init__.py +6 -0
- autobyteus/agent/streaming/events/stream_event_payloads.py +284 -0
- autobyteus/agent/streaming/events/stream_events.py +141 -0
- autobyteus/agent/streaming/handlers/__init__.py +15 -0
- autobyteus/agent/streaming/handlers/api_tool_call_streaming_response_handler.py +303 -0
- autobyteus/agent/streaming/handlers/parsing_streaming_response_handler.py +107 -0
- autobyteus/agent/streaming/handlers/pass_through_streaming_response_handler.py +107 -0
- autobyteus/agent/streaming/handlers/streaming_handler_factory.py +177 -0
- autobyteus/agent/streaming/handlers/streaming_response_handler.py +58 -0
- autobyteus/agent/streaming/parser/__init__.py +61 -0
- autobyteus/agent/streaming/parser/event_emitter.py +181 -0
- autobyteus/agent/streaming/parser/events.py +4 -0
- autobyteus/agent/streaming/parser/invocation_adapter.py +4 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/__init__.py +19 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/base.py +32 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/default.py +34 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/gemini.py +31 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/openai.py +64 -0
- autobyteus/agent/streaming/parser/json_parsing_strategies/registry.py +75 -0
- autobyteus/agent/streaming/parser/parser_context.py +227 -0
- autobyteus/agent/streaming/parser/parser_factory.py +132 -0
- autobyteus/agent/streaming/parser/sentinel_format.py +7 -0
- autobyteus/agent/streaming/parser/state_factory.py +62 -0
- autobyteus/agent/streaming/parser/states/__init__.py +1 -0
- autobyteus/agent/streaming/parser/states/base_state.py +60 -0
- autobyteus/agent/streaming/parser/states/custom_xml_tag_run_bash_parsing_state.py +38 -0
- autobyteus/agent/streaming/parser/states/custom_xml_tag_write_file_parsing_state.py +55 -0
- autobyteus/agent/streaming/parser/states/delimited_content_state.py +146 -0
- autobyteus/agent/streaming/parser/states/json_initialization_state.py +144 -0
- autobyteus/agent/streaming/parser/states/json_tool_parsing_state.py +137 -0
- autobyteus/agent/streaming/parser/states/sentinel_content_state.py +30 -0
- autobyteus/agent/streaming/parser/states/sentinel_initialization_state.py +117 -0
- autobyteus/agent/streaming/parser/states/text_state.py +78 -0
- autobyteus/agent/streaming/parser/states/xml_patch_file_tool_parsing_state.py +328 -0
- autobyteus/agent/streaming/parser/states/xml_run_bash_tool_parsing_state.py +129 -0
- autobyteus/agent/streaming/parser/states/xml_tag_initialization_state.py +151 -0
- autobyteus/agent/streaming/parser/states/xml_tool_parsing_state.py +63 -0
- autobyteus/agent/streaming/parser/states/xml_write_file_tool_parsing_state.py +343 -0
- autobyteus/agent/streaming/parser/strategies/__init__.py +17 -0
- autobyteus/agent/streaming/parser/strategies/base.py +24 -0
- autobyteus/agent/streaming/parser/strategies/json_tool_strategy.py +26 -0
- autobyteus/agent/streaming/parser/strategies/registry.py +28 -0
- autobyteus/agent/streaming/parser/strategies/sentinel_strategy.py +23 -0
- autobyteus/agent/streaming/parser/strategies/xml_tag_strategy.py +21 -0
- autobyteus/agent/streaming/parser/stream_scanner.py +167 -0
- autobyteus/agent/streaming/parser/streaming_parser.py +212 -0
- autobyteus/agent/streaming/parser/tool_call_parsing.py +4 -0
- autobyteus/agent/streaming/parser/tool_constants.py +7 -0
- autobyteus/agent/streaming/parser/tool_syntax_registry.py +4 -0
- autobyteus/agent/streaming/parser/xml_tool_parsing_state_registry.py +55 -0
- autobyteus/agent/streaming/parsing_streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/pass_through_streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/queue_streamer.py +3 -57
- autobyteus/agent/streaming/segments/__init__.py +5 -0
- autobyteus/agent/streaming/segments/segment_events.py +82 -0
- autobyteus/agent/streaming/stream_event_payloads.py +2 -223
- autobyteus/agent/streaming/stream_events.py +3 -140
- autobyteus/agent/streaming/streaming_handler_factory.py +4 -0
- autobyteus/agent/streaming/streaming_response_handler.py +4 -0
- autobyteus/agent/streaming/streams/__init__.py +5 -0
- autobyteus/agent/streaming/streams/agent_event_stream.py +197 -0
- autobyteus/agent/streaming/utils/__init__.py +5 -0
- autobyteus/agent/streaming/utils/queue_streamer.py +59 -0
- autobyteus/agent/system_prompt_processor/__init__.py +2 -0
- autobyteus/agent/system_prompt_processor/available_skills_processor.py +96 -0
- autobyteus/agent/system_prompt_processor/base_processor.py +1 -1
- autobyteus/agent/system_prompt_processor/processor_meta.py +15 -2
- autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +39 -58
- autobyteus/agent/token_budget.py +56 -0
- autobyteus/agent/tool_execution_result_processor/memory_ingest_tool_result_processor.py +29 -0
- autobyteus/agent/tool_invocation.py +16 -40
- autobyteus/agent/tool_invocation_preprocessor/__init__.py +9 -0
- autobyteus/agent/tool_invocation_preprocessor/base_preprocessor.py +45 -0
- autobyteus/agent/tool_invocation_preprocessor/processor_definition.py +15 -0
- autobyteus/agent/tool_invocation_preprocessor/processor_meta.py +33 -0
- autobyteus/agent/tool_invocation_preprocessor/processor_registry.py +60 -0
- autobyteus/agent/utils/wait_for_idle.py +12 -14
- autobyteus/agent/workspace/base_workspace.py +6 -27
- autobyteus/agent_team/agent_team.py +3 -3
- autobyteus/agent_team/agent_team_builder.py +1 -41
- autobyteus/agent_team/bootstrap_steps/__init__.py +0 -4
- autobyteus/agent_team/bootstrap_steps/agent_configuration_preparation_step.py +8 -18
- autobyteus/agent_team/bootstrap_steps/agent_team_bootstrapper.py +4 -16
- autobyteus/agent_team/bootstrap_steps/base_agent_team_bootstrap_step.py +1 -2
- autobyteus/agent_team/bootstrap_steps/coordinator_initialization_step.py +1 -2
- autobyteus/agent_team/bootstrap_steps/task_notifier_initialization_step.py +1 -2
- autobyteus/agent_team/bootstrap_steps/team_context_initialization_step.py +4 -4
- autobyteus/agent_team/context/agent_team_config.py +6 -3
- autobyteus/agent_team/context/agent_team_context.py +25 -3
- autobyteus/agent_team/context/agent_team_runtime_state.py +9 -6
- autobyteus/agent_team/events/__init__.py +11 -0
- autobyteus/agent_team/events/agent_team_event_dispatcher.py +22 -9
- autobyteus/agent_team/events/agent_team_events.py +16 -0
- autobyteus/agent_team/events/event_store.py +57 -0
- autobyteus/agent_team/factory/agent_team_factory.py +8 -0
- autobyteus/agent_team/handlers/inter_agent_message_request_event_handler.py +18 -2
- autobyteus/agent_team/handlers/lifecycle_agent_team_event_handler.py +21 -5
- autobyteus/agent_team/handlers/process_user_message_event_handler.py +17 -8
- autobyteus/agent_team/handlers/tool_approval_team_event_handler.py +19 -4
- autobyteus/agent_team/runtime/agent_team_runtime.py +41 -10
- autobyteus/agent_team/runtime/agent_team_worker.py +69 -5
- autobyteus/agent_team/status/__init__.py +14 -0
- autobyteus/agent_team/status/agent_team_status.py +18 -0
- autobyteus/agent_team/status/agent_team_status_manager.py +33 -0
- autobyteus/agent_team/status/status_deriver.py +62 -0
- autobyteus/agent_team/status/status_update_utils.py +42 -0
- autobyteus/agent_team/streaming/__init__.py +2 -2
- autobyteus/agent_team/streaming/agent_team_event_notifier.py +6 -6
- autobyteus/agent_team/streaming/agent_team_stream_event_payloads.py +4 -4
- autobyteus/agent_team/streaming/agent_team_stream_events.py +3 -3
- autobyteus/agent_team/system_prompt_processor/__init__.py +6 -0
- autobyteus/agent_team/system_prompt_processor/team_manifest_injector_processor.py +76 -0
- autobyteus/agent_team/task_notification/task_notification_mode.py +19 -0
- autobyteus/agent_team/utils/wait_for_idle.py +4 -4
- autobyteus/cli/agent_cli.py +18 -10
- autobyteus/cli/agent_team_tui/app.py +14 -11
- autobyteus/cli/agent_team_tui/state.py +13 -15
- autobyteus/cli/agent_team_tui/widgets/agent_list_sidebar.py +15 -15
- autobyteus/cli/agent_team_tui/widgets/focus_pane.py +143 -36
- autobyteus/cli/agent_team_tui/widgets/renderables.py +1 -1
- autobyteus/cli/agent_team_tui/widgets/shared.py +25 -25
- autobyteus/cli/cli_display.py +193 -44
- autobyteus/cli/workflow_tui/app.py +9 -10
- autobyteus/cli/workflow_tui/state.py +14 -16
- autobyteus/cli/workflow_tui/widgets/agent_list_sidebar.py +15 -15
- autobyteus/cli/workflow_tui/widgets/focus_pane.py +137 -35
- autobyteus/cli/workflow_tui/widgets/renderables.py +1 -1
- autobyteus/cli/workflow_tui/widgets/shared.py +25 -25
- autobyteus/clients/autobyteus_client.py +94 -1
- autobyteus/events/event_types.py +11 -18
- autobyteus/llm/api/autobyteus_llm.py +33 -29
- autobyteus/llm/api/claude_llm.py +142 -36
- autobyteus/llm/api/gemini_llm.py +163 -59
- autobyteus/llm/api/grok_llm.py +1 -1
- autobyteus/llm/api/minimax_llm.py +26 -0
- autobyteus/llm/api/mistral_llm.py +113 -87
- autobyteus/llm/api/ollama_llm.py +9 -42
- autobyteus/llm/api/openai_compatible_llm.py +127 -91
- autobyteus/llm/api/openai_llm.py +3 -3
- autobyteus/llm/api/openai_responses_llm.py +324 -0
- autobyteus/llm/api/zhipu_llm.py +21 -2
- autobyteus/llm/autobyteus_provider.py +70 -60
- autobyteus/llm/base_llm.py +85 -81
- autobyteus/llm/converters/__init__.py +14 -0
- autobyteus/llm/converters/anthropic_tool_call_converter.py +37 -0
- autobyteus/llm/converters/gemini_tool_call_converter.py +57 -0
- autobyteus/llm/converters/mistral_tool_call_converter.py +37 -0
- autobyteus/llm/converters/openai_tool_call_converter.py +38 -0
- autobyteus/llm/extensions/base_extension.py +6 -12
- autobyteus/llm/extensions/token_usage_tracking_extension.py +45 -18
- autobyteus/llm/llm_factory.py +282 -204
- autobyteus/llm/lmstudio_provider.py +60 -49
- autobyteus/llm/models.py +35 -2
- autobyteus/llm/ollama_provider.py +60 -49
- autobyteus/llm/ollama_provider_resolver.py +0 -1
- autobyteus/llm/prompt_renderers/__init__.py +19 -0
- autobyteus/llm/prompt_renderers/anthropic_prompt_renderer.py +104 -0
- autobyteus/llm/prompt_renderers/autobyteus_prompt_renderer.py +19 -0
- autobyteus/llm/prompt_renderers/base_prompt_renderer.py +10 -0
- autobyteus/llm/prompt_renderers/gemini_prompt_renderer.py +63 -0
- autobyteus/llm/prompt_renderers/mistral_prompt_renderer.py +87 -0
- autobyteus/llm/prompt_renderers/ollama_prompt_renderer.py +51 -0
- autobyteus/llm/prompt_renderers/openai_chat_renderer.py +97 -0
- autobyteus/llm/prompt_renderers/openai_responses_renderer.py +101 -0
- autobyteus/llm/providers.py +1 -3
- autobyteus/llm/token_counter/claude_token_counter.py +56 -25
- autobyteus/llm/token_counter/mistral_token_counter.py +12 -8
- autobyteus/llm/token_counter/openai_token_counter.py +24 -5
- autobyteus/llm/token_counter/token_counter_factory.py +12 -5
- autobyteus/llm/utils/llm_config.py +6 -12
- autobyteus/llm/utils/media_payload_formatter.py +27 -20
- autobyteus/llm/utils/messages.py +55 -3
- autobyteus/llm/utils/response_types.py +3 -0
- autobyteus/llm/utils/tool_call_delta.py +31 -0
- autobyteus/memory/__init__.py +35 -0
- autobyteus/memory/compaction/__init__.py +9 -0
- autobyteus/memory/compaction/compaction_result.py +8 -0
- autobyteus/memory/compaction/compactor.py +89 -0
- autobyteus/memory/compaction/summarizer.py +11 -0
- autobyteus/memory/compaction_snapshot_builder.py +84 -0
- autobyteus/memory/memory_manager.py +205 -0
- autobyteus/memory/models/__init__.py +14 -0
- autobyteus/memory/models/episodic_item.py +41 -0
- autobyteus/memory/models/memory_types.py +7 -0
- autobyteus/memory/models/raw_trace_item.py +79 -0
- autobyteus/memory/models/semantic_item.py +41 -0
- autobyteus/memory/models/tool_interaction.py +20 -0
- autobyteus/memory/path_resolver.py +27 -0
- autobyteus/memory/policies/__init__.py +5 -0
- autobyteus/memory/policies/compaction_policy.py +16 -0
- autobyteus/memory/restore/__init__.py +1 -0
- autobyteus/memory/restore/working_context_snapshot_bootstrapper.py +61 -0
- autobyteus/memory/retrieval/__init__.py +7 -0
- autobyteus/memory/retrieval/memory_bundle.py +11 -0
- autobyteus/memory/retrieval/retriever.py +13 -0
- autobyteus/memory/store/__init__.py +9 -0
- autobyteus/memory/store/base_store.py +14 -0
- autobyteus/memory/store/file_store.py +98 -0
- autobyteus/memory/store/working_context_snapshot_store.py +28 -0
- autobyteus/memory/tool_interaction_builder.py +46 -0
- autobyteus/memory/turn_tracker.py +9 -0
- autobyteus/memory/working_context_snapshot.py +69 -0
- autobyteus/memory/working_context_snapshot_serializer.py +135 -0
- autobyteus/multimedia/audio/api/autobyteus_audio_client.py +19 -5
- autobyteus/multimedia/audio/api/gemini_audio_client.py +109 -16
- autobyteus/multimedia/audio/audio_client_factory.py +47 -9
- autobyteus/multimedia/audio/audio_model.py +2 -1
- autobyteus/multimedia/image/api/autobyteus_image_client.py +19 -5
- autobyteus/multimedia/image/api/gemini_image_client.py +39 -17
- autobyteus/multimedia/image/api/openai_image_client.py +125 -43
- autobyteus/multimedia/image/autobyteus_image_provider.py +2 -1
- autobyteus/multimedia/image/image_client_factory.py +47 -15
- autobyteus/multimedia/image/image_model.py +5 -2
- autobyteus/multimedia/providers.py +3 -2
- autobyteus/skills/loader.py +71 -0
- autobyteus/skills/model.py +11 -0
- autobyteus/skills/registry.py +70 -0
- autobyteus/task_management/tools/todo_tools/add_todo.py +2 -2
- autobyteus/task_management/tools/todo_tools/create_todo_list.py +2 -2
- autobyteus/task_management/tools/todo_tools/update_todo_status.py +2 -2
- autobyteus/tools/__init__.py +34 -47
- autobyteus/tools/base_tool.py +7 -0
- autobyteus/tools/file/__init__.py +2 -6
- autobyteus/tools/file/patch_file.py +149 -0
- autobyteus/tools/file/read_file.py +36 -5
- autobyteus/tools/file/write_file.py +4 -1
- autobyteus/tools/functional_tool.py +43 -6
- autobyteus/tools/mcp/__init__.py +2 -0
- autobyteus/tools/mcp/config_service.py +5 -1
- autobyteus/tools/mcp/server/__init__.py +2 -0
- autobyteus/tools/mcp/server/http_managed_mcp_server.py +1 -1
- autobyteus/tools/mcp/server/websocket_managed_mcp_server.py +141 -0
- autobyteus/tools/mcp/server_instance_manager.py +8 -1
- autobyteus/tools/mcp/types.py +61 -0
- autobyteus/tools/multimedia/audio_tools.py +70 -17
- autobyteus/tools/multimedia/download_media_tool.py +18 -4
- autobyteus/tools/multimedia/image_tools.py +246 -62
- autobyteus/tools/operation_executor/journal_manager.py +107 -0
- autobyteus/tools/operation_executor/operation_event_buffer.py +57 -0
- autobyteus/tools/operation_executor/operation_event_producer.py +29 -0
- autobyteus/tools/operation_executor/operation_executor.py +58 -0
- autobyteus/tools/registry/tool_definition.py +43 -2
- autobyteus/tools/skill/load_skill.py +50 -0
- autobyteus/tools/terminal/__init__.py +45 -0
- autobyteus/tools/terminal/ansi_utils.py +32 -0
- autobyteus/tools/terminal/background_process_manager.py +233 -0
- autobyteus/tools/terminal/output_buffer.py +105 -0
- autobyteus/tools/terminal/prompt_detector.py +63 -0
- autobyteus/tools/terminal/pty_session.py +241 -0
- autobyteus/tools/terminal/session_factory.py +20 -0
- autobyteus/tools/terminal/terminal_session_manager.py +226 -0
- autobyteus/tools/terminal/tools/__init__.py +13 -0
- autobyteus/tools/terminal/tools/get_process_output.py +81 -0
- autobyteus/tools/terminal/tools/run_bash.py +109 -0
- autobyteus/tools/terminal/tools/start_background_process.py +104 -0
- autobyteus/tools/terminal/tools/stop_background_process.py +67 -0
- autobyteus/tools/terminal/types.py +54 -0
- autobyteus/tools/terminal/wsl_tmux_session.py +221 -0
- autobyteus/tools/terminal/wsl_utils.py +156 -0
- autobyteus/tools/transaction_management/backup_handler.py +48 -0
- autobyteus/tools/transaction_management/operation_lifecycle_manager.py +62 -0
- autobyteus/tools/usage/__init__.py +1 -2
- autobyteus/tools/usage/formatters/__init__.py +17 -1
- autobyteus/tools/usage/formatters/base_formatter.py +8 -0
- autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +2 -2
- autobyteus/tools/usage/formatters/mistral_json_schema_formatter.py +18 -0
- autobyteus/tools/usage/formatters/patch_file_xml_example_formatter.py +64 -0
- autobyteus/tools/usage/formatters/patch_file_xml_schema_formatter.py +31 -0
- autobyteus/tools/usage/formatters/run_bash_xml_example_formatter.py +32 -0
- autobyteus/tools/usage/formatters/run_bash_xml_schema_formatter.py +36 -0
- autobyteus/tools/usage/formatters/write_file_xml_example_formatter.py +53 -0
- autobyteus/tools/usage/formatters/write_file_xml_schema_formatter.py +31 -0
- autobyteus/tools/usage/providers/tool_manifest_provider.py +10 -10
- autobyteus/tools/usage/registries/__init__.py +1 -3
- autobyteus/tools/usage/registries/tool_formatting_registry.py +115 -8
- autobyteus/tools/usage/tool_schema_provider.py +51 -0
- autobyteus/tools/web/__init__.py +4 -0
- autobyteus/tools/web/read_url_tool.py +80 -0
- autobyteus/utils/diff_utils.py +271 -0
- autobyteus/utils/download_utils.py +109 -0
- autobyteus/utils/file_utils.py +57 -2
- autobyteus/utils/gemini_helper.py +64 -0
- autobyteus/utils/gemini_model_mapping.py +71 -0
- autobyteus/utils/llm_output_formatter.py +75 -0
- autobyteus/utils/tool_call_format.py +36 -0
- autobyteus/workflow/agentic_workflow.py +3 -3
- autobyteus/workflow/bootstrap_steps/agent_tool_injection_step.py +2 -2
- autobyteus/workflow/bootstrap_steps/base_workflow_bootstrap_step.py +2 -2
- autobyteus/workflow/bootstrap_steps/coordinator_initialization_step.py +2 -2
- autobyteus/workflow/bootstrap_steps/coordinator_prompt_preparation_step.py +3 -9
- autobyteus/workflow/bootstrap_steps/workflow_bootstrapper.py +6 -6
- autobyteus/workflow/bootstrap_steps/workflow_runtime_queue_initialization_step.py +2 -2
- autobyteus/workflow/context/workflow_context.py +3 -3
- autobyteus/workflow/context/workflow_runtime_state.py +5 -5
- autobyteus/workflow/events/workflow_event_dispatcher.py +5 -5
- autobyteus/workflow/handlers/lifecycle_workflow_event_handler.py +3 -3
- autobyteus/workflow/handlers/process_user_message_event_handler.py +5 -5
- autobyteus/workflow/handlers/tool_approval_workflow_event_handler.py +2 -2
- autobyteus/workflow/runtime/workflow_runtime.py +8 -8
- autobyteus/workflow/runtime/workflow_worker.py +3 -3
- autobyteus/workflow/status/__init__.py +11 -0
- autobyteus/workflow/status/workflow_status.py +19 -0
- autobyteus/workflow/status/workflow_status_manager.py +48 -0
- autobyteus/workflow/streaming/__init__.py +2 -2
- autobyteus/workflow/streaming/workflow_event_notifier.py +7 -7
- autobyteus/workflow/streaming/workflow_stream_event_payloads.py +4 -4
- autobyteus/workflow/streaming/workflow_stream_events.py +3 -3
- autobyteus/workflow/utils/wait_for_idle.py +4 -4
- autobyteus-1.3.0.dist-info/METADATA +293 -0
- autobyteus-1.3.0.dist-info/RECORD +606 -0
- {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/WHEEL +1 -1
- {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/top_level.txt +0 -1
- autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +0 -57
- autobyteus/agent/hooks/__init__.py +0 -16
- autobyteus/agent/hooks/base_phase_hook.py +0 -78
- autobyteus/agent/hooks/hook_definition.py +0 -36
- autobyteus/agent/hooks/hook_meta.py +0 -37
- autobyteus/agent/hooks/hook_registry.py +0 -106
- autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +0 -103
- autobyteus/agent/phases/__init__.py +0 -18
- autobyteus/agent/phases/discover.py +0 -53
- autobyteus/agent/phases/manager.py +0 -265
- autobyteus/agent/phases/transition_decorator.py +0 -40
- autobyteus/agent/phases/transition_info.py +0 -33
- autobyteus/agent/remote_agent.py +0 -244
- autobyteus/agent/workspace/workspace_definition.py +0 -36
- autobyteus/agent/workspace/workspace_meta.py +0 -37
- autobyteus/agent/workspace/workspace_registry.py +0 -72
- autobyteus/agent_team/bootstrap_steps/agent_team_runtime_queue_initialization_step.py +0 -25
- autobyteus/agent_team/bootstrap_steps/coordinator_prompt_preparation_step.py +0 -85
- autobyteus/agent_team/phases/__init__.py +0 -11
- autobyteus/agent_team/phases/agent_team_operational_phase.py +0 -19
- autobyteus/agent_team/phases/agent_team_phase_manager.py +0 -48
- autobyteus/llm/api/bedrock_llm.py +0 -92
- autobyteus/llm/api/groq_llm.py +0 -94
- autobyteus/llm/api/nvidia_llm.py +0 -108
- autobyteus/llm/utils/token_pricing_config.py +0 -87
- autobyteus/rpc/__init__.py +0 -73
- autobyteus/rpc/client/__init__.py +0 -17
- autobyteus/rpc/client/abstract_client_connection.py +0 -124
- autobyteus/rpc/client/client_connection_manager.py +0 -153
- autobyteus/rpc/client/sse_client_connection.py +0 -306
- autobyteus/rpc/client/stdio_client_connection.py +0 -280
- autobyteus/rpc/config/__init__.py +0 -13
- autobyteus/rpc/config/agent_server_config.py +0 -153
- autobyteus/rpc/config/agent_server_registry.py +0 -152
- autobyteus/rpc/hosting.py +0 -244
- autobyteus/rpc/protocol.py +0 -244
- autobyteus/rpc/server/__init__.py +0 -20
- autobyteus/rpc/server/agent_server_endpoint.py +0 -181
- autobyteus/rpc/server/base_method_handler.py +0 -40
- autobyteus/rpc/server/method_handlers.py +0 -259
- autobyteus/rpc/server/sse_server_handler.py +0 -182
- autobyteus/rpc/server/stdio_server_handler.py +0 -151
- autobyteus/rpc/server_main.py +0 -198
- autobyteus/rpc/transport_type.py +0 -13
- autobyteus/tools/bash/__init__.py +0 -2
- autobyteus/tools/bash/bash_executor.py +0 -100
- autobyteus/tools/browser/__init__.py +0 -2
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +0 -75
- autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +0 -30
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +0 -154
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +0 -89
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +0 -107
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +0 -14
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +0 -26
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +0 -14
- autobyteus/tools/browser/session_aware/shared_browser_session.py +0 -11
- autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +0 -25
- autobyteus/tools/browser/session_aware/web_element_action.py +0 -20
- autobyteus/tools/browser/standalone/__init__.py +0 -6
- autobyteus/tools/browser/standalone/factory/__init__.py +0 -0
- autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +0 -25
- autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +0 -14
- autobyteus/tools/browser/standalone/navigate_to.py +0 -84
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +0 -101
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +0 -169
- autobyteus/tools/browser/standalone/webpage_reader.py +0 -105
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +0 -105
- autobyteus/tools/file/edit_file.py +0 -200
- autobyteus/tools/file/list_directory.py +0 -168
- autobyteus/tools/file/search_files.py +0 -188
- autobyteus/tools/timer.py +0 -175
- autobyteus/tools/usage/parsers/__init__.py +0 -22
- autobyteus/tools/usage/parsers/_json_extractor.py +0 -99
- autobyteus/tools/usage/parsers/_string_decoders.py +0 -18
- autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +0 -10
- autobyteus/tools/usage/parsers/base_parser.py +0 -41
- autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +0 -83
- autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +0 -316
- autobyteus/tools/usage/parsers/exceptions.py +0 -13
- autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +0 -77
- autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +0 -149
- autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +0 -59
- autobyteus/tools/usage/registries/tool_usage_parser_registry.py +0 -62
- autobyteus/workflow/phases/__init__.py +0 -11
- autobyteus/workflow/phases/workflow_operational_phase.py +0 -19
- autobyteus/workflow/phases/workflow_phase_manager.py +0 -48
- autobyteus-1.2.1.dist-info/METADATA +0 -205
- autobyteus-1.2.1.dist-info/RECORD +0 -511
- examples/__init__.py +0 -1
- examples/agent_team/__init__.py +0 -1
- examples/discover_phase_transitions.py +0 -104
- examples/run_agentic_software_engineer.py +0 -239
- examples/run_browser_agent.py +0 -262
- examples/run_google_slides_agent.py +0 -287
- examples/run_mcp_browser_client.py +0 -174
- examples/run_mcp_google_slides_client.py +0 -270
- examples/run_mcp_list_tools.py +0 -189
- examples/run_poem_writer.py +0 -284
- examples/run_sqlite_agent.py +0 -295
- /autobyteus/{tools/browser/session_aware → skills}/__init__.py +0 -0
- /autobyteus/tools/{browser/session_aware/factory → skill}/__init__.py +0 -0
- {autobyteus-1.2.1.dist-info → autobyteus-1.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""
|
|
2
|
+
DelimitedContentState: Base state for content blocks terminated by a closing tag.
|
|
3
|
+
|
|
4
|
+
Provides streaming-safe emission with a holdback tail to prevent partial
|
|
5
|
+
closing tags from being emitted.
|
|
6
|
+
"""
|
|
7
|
+
from typing import TYPE_CHECKING, Optional, Dict
|
|
8
|
+
|
|
9
|
+
from .base_state import BaseState
|
|
10
|
+
from ..events import SegmentType
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from ..parser_context import ParserContext
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class DelimitedContentState(BaseState):
|
|
17
|
+
"""
|
|
18
|
+
Base class for parsing delimited content blocks.
|
|
19
|
+
|
|
20
|
+
Subclasses must define:
|
|
21
|
+
- CLOSING_TAG: The closing tag string (e.g., "</file>")
|
|
22
|
+
- SEGMENT_TYPE: SegmentType for emitted segments
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
CLOSING_TAG = ""
|
|
26
|
+
SEGMENT_TYPE: Optional[SegmentType] = None
|
|
27
|
+
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
context: "ParserContext",
|
|
31
|
+
opening_tag: str,
|
|
32
|
+
closing_tag_override: Optional[str] = None,
|
|
33
|
+
):
|
|
34
|
+
super().__init__(context)
|
|
35
|
+
self._opening_tag = opening_tag
|
|
36
|
+
self._segment_started = False
|
|
37
|
+
self._tail = ""
|
|
38
|
+
self._closing_tag = closing_tag_override if closing_tag_override is not None else self.CLOSING_TAG
|
|
39
|
+
self._closing_tag_lower = self._closing_tag.lower()
|
|
40
|
+
self._holdback_len = max(len(self._closing_tag) - 1, 0)
|
|
41
|
+
|
|
42
|
+
def _can_start_segment(self) -> bool:
|
|
43
|
+
"""Return False to emit opening tag as text and abort."""
|
|
44
|
+
return True
|
|
45
|
+
|
|
46
|
+
def _get_start_metadata(self) -> Dict[str, str]:
|
|
47
|
+
"""Metadata to include on segment start."""
|
|
48
|
+
return {}
|
|
49
|
+
|
|
50
|
+
def _opening_content(self) -> Optional[str]:
|
|
51
|
+
"""Optional content to emit immediately after segment start."""
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
def _on_segment_complete(self) -> None:
|
|
55
|
+
"""Hook invoked just before segment end is emitted."""
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
def _should_emit_closing_tag(self) -> bool:
|
|
59
|
+
"""Whether to emit the closing tag as content."""
|
|
60
|
+
return False
|
|
61
|
+
|
|
62
|
+
def run(self) -> None:
|
|
63
|
+
from .text_state import TextState
|
|
64
|
+
|
|
65
|
+
if not self._segment_started:
|
|
66
|
+
if not self._can_start_segment():
|
|
67
|
+
self.context.append_text_segment(self._opening_tag)
|
|
68
|
+
self.context.transition_to(TextState(self.context))
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
if self.SEGMENT_TYPE is None:
|
|
72
|
+
raise RuntimeError("SEGMENT_TYPE is not defined for DelimitedContentState.")
|
|
73
|
+
|
|
74
|
+
self.context.emit_segment_start(self.SEGMENT_TYPE, **self._get_start_metadata())
|
|
75
|
+
self._segment_started = True
|
|
76
|
+
|
|
77
|
+
opening_content = self._opening_content()
|
|
78
|
+
if opening_content:
|
|
79
|
+
self.context.emit_segment_content(opening_content)
|
|
80
|
+
|
|
81
|
+
if not self.context.has_more_chars():
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
available = self.context.consume_remaining()
|
|
85
|
+
combined = self._tail + available
|
|
86
|
+
|
|
87
|
+
if combined:
|
|
88
|
+
idx = combined.lower().find(self._closing_tag_lower)
|
|
89
|
+
else:
|
|
90
|
+
idx = -1
|
|
91
|
+
|
|
92
|
+
if idx != -1:
|
|
93
|
+
content_before = combined[:idx]
|
|
94
|
+
if content_before:
|
|
95
|
+
self.context.emit_segment_content(content_before)
|
|
96
|
+
|
|
97
|
+
if self._should_emit_closing_tag() and self._closing_tag:
|
|
98
|
+
self.context.emit_segment_content(self._closing_tag)
|
|
99
|
+
|
|
100
|
+
tail_len = len(self._tail)
|
|
101
|
+
closing_len = len(self._closing_tag)
|
|
102
|
+
if idx < tail_len:
|
|
103
|
+
consumed_from_available = idx + closing_len - tail_len
|
|
104
|
+
else:
|
|
105
|
+
consumed_from_available = (idx - tail_len) + closing_len
|
|
106
|
+
|
|
107
|
+
extra = len(available) - consumed_from_available
|
|
108
|
+
if extra > 0:
|
|
109
|
+
self.context.rewind_by(extra)
|
|
110
|
+
|
|
111
|
+
self._tail = ""
|
|
112
|
+
self._on_segment_complete()
|
|
113
|
+
self.context.emit_segment_end()
|
|
114
|
+
self.context.transition_to(TextState(self.context))
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
if self._holdback_len == 0:
|
|
118
|
+
if combined:
|
|
119
|
+
self.context.emit_segment_content(combined)
|
|
120
|
+
self._tail = ""
|
|
121
|
+
return
|
|
122
|
+
|
|
123
|
+
if len(combined) > self._holdback_len:
|
|
124
|
+
safe = combined[:-self._holdback_len]
|
|
125
|
+
if safe:
|
|
126
|
+
self.context.emit_segment_content(safe)
|
|
127
|
+
self._tail = combined[-self._holdback_len:]
|
|
128
|
+
else:
|
|
129
|
+
self._tail = combined
|
|
130
|
+
|
|
131
|
+
def finalize(self) -> None:
|
|
132
|
+
from .text_state import TextState
|
|
133
|
+
|
|
134
|
+
remaining = self.context.consume_remaining() if self.context.has_more_chars() else ""
|
|
135
|
+
|
|
136
|
+
if not self._segment_started:
|
|
137
|
+
text = self._opening_tag + self._tail + remaining
|
|
138
|
+
if text:
|
|
139
|
+
self.context.append_text_segment(text)
|
|
140
|
+
else:
|
|
141
|
+
if self._tail or remaining:
|
|
142
|
+
self.context.emit_segment_content(self._tail + remaining)
|
|
143
|
+
self._tail = ""
|
|
144
|
+
self.context.emit_segment_end()
|
|
145
|
+
|
|
146
|
+
self.context.transition_to(TextState(self.context))
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
JsonInitializationState: Analyzes potential JSON tool calls after a '{' or '[' is detected.
|
|
3
|
+
|
|
4
|
+
This state buffers characters to determine if a JSON structure is a tool call
|
|
5
|
+
based on a signature check strategy. Used for providers like OpenAI that use
|
|
6
|
+
JSON format instead of XML.
|
|
7
|
+
"""
|
|
8
|
+
from typing import TYPE_CHECKING, Optional, List
|
|
9
|
+
|
|
10
|
+
from .base_state import BaseState
|
|
11
|
+
from ..events import SegmentType
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from ..parser_context import ParserContext
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class JsonToolSignatureChecker:
|
|
18
|
+
"""
|
|
19
|
+
Checks if a JSON buffer matches known tool call signatures.
|
|
20
|
+
|
|
21
|
+
Common JSON tool call formats:
|
|
22
|
+
- OpenAI: {"name": "tool_name", "arguments": {...}}
|
|
23
|
+
- Anthropic: Similar structure
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
- 'match': Buffer matches a tool signature
|
|
27
|
+
- 'partial': Buffer could still match (keep buffering)
|
|
28
|
+
- 'no_match': Buffer definitely not a tool call
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, patterns: Optional[List[str]] = None):
|
|
32
|
+
"""
|
|
33
|
+
Initialize with custom patterns or defaults.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
patterns: List of JSON prefixes that indicate tool calls.
|
|
37
|
+
Uses defaults if not provided.
|
|
38
|
+
"""
|
|
39
|
+
from ..parser_context import ParserConfig
|
|
40
|
+
self._patterns = patterns or ParserConfig.DEFAULT_JSON_PATTERNS
|
|
41
|
+
|
|
42
|
+
def check_signature(self, buffer: str) -> str:
|
|
43
|
+
"""
|
|
44
|
+
Check if the buffer matches a tool call signature.
|
|
45
|
+
|
|
46
|
+
Returns 'match', 'partial', or 'no_match'.
|
|
47
|
+
"""
|
|
48
|
+
# Normalize whitespace for checking
|
|
49
|
+
normalized = buffer.replace(" ", "").replace("\n", "").replace("\t", "")
|
|
50
|
+
|
|
51
|
+
for pattern in self._patterns:
|
|
52
|
+
normalized_pattern = pattern.replace(" ", "")
|
|
53
|
+
|
|
54
|
+
# Exact prefix match - it's a tool call
|
|
55
|
+
if normalized.startswith(normalized_pattern):
|
|
56
|
+
return 'match'
|
|
57
|
+
|
|
58
|
+
# Could still become this pattern
|
|
59
|
+
if normalized_pattern.startswith(normalized):
|
|
60
|
+
return 'partial'
|
|
61
|
+
|
|
62
|
+
# Check if we're still in the opening portion
|
|
63
|
+
# Allow for whitespace variations like { "name" or {\n"name"
|
|
64
|
+
if len(normalized) < 8: # Short buffer, still checking
|
|
65
|
+
if normalized in ['', '{', '[', '{"', '[{', '{"n', '{"na', '{"nam']:
|
|
66
|
+
return 'partial'
|
|
67
|
+
|
|
68
|
+
return 'no_match'
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class JsonInitializationState(BaseState):
|
|
72
|
+
"""
|
|
73
|
+
Analyzes a potential JSON tool call to determine if it's a known format.
|
|
74
|
+
|
|
75
|
+
This state is entered when a '{' or '[' is detected and JSON parsing is enabled.
|
|
76
|
+
It buffers characters to check for tool call signatures.
|
|
77
|
+
"""
|
|
78
|
+
|
|
79
|
+
def __init__(self, context: "ParserContext"):
|
|
80
|
+
super().__init__(context)
|
|
81
|
+
# Consume the trigger character that caused this transition
|
|
82
|
+
trigger = self.context.peek_char()
|
|
83
|
+
self.context.advance()
|
|
84
|
+
self._signature_buffer = trigger if trigger else ""
|
|
85
|
+
# Use patterns from config
|
|
86
|
+
self._checker = JsonToolSignatureChecker(context.json_tool_patterns)
|
|
87
|
+
|
|
88
|
+
def run(self) -> None:
|
|
89
|
+
"""
|
|
90
|
+
Buffer characters and check for tool call signatures.
|
|
91
|
+
|
|
92
|
+
If a match is found, transitions to XmlToolParsingState (JSON mode).
|
|
93
|
+
If no match, reverts the buffer to text.
|
|
94
|
+
"""
|
|
95
|
+
from .text_state import TextState
|
|
96
|
+
from .json_tool_parsing_state import JsonToolParsingState
|
|
97
|
+
|
|
98
|
+
while self.context.has_more_chars():
|
|
99
|
+
char = self.context.peek_char()
|
|
100
|
+
self._signature_buffer += char
|
|
101
|
+
self.context.advance()
|
|
102
|
+
|
|
103
|
+
match = self._checker.check_signature(self._signature_buffer)
|
|
104
|
+
|
|
105
|
+
if match == 'match':
|
|
106
|
+
# Found a tool signature
|
|
107
|
+
if self.context.parse_tool_calls:
|
|
108
|
+
if self.context.get_current_segment_type() == SegmentType.TEXT:
|
|
109
|
+
self.context.emit_segment_end()
|
|
110
|
+
# Signature buffer already consumed by this state; pass it along.
|
|
111
|
+
self.context.transition_to(
|
|
112
|
+
JsonToolParsingState(
|
|
113
|
+
self.context,
|
|
114
|
+
self._signature_buffer,
|
|
115
|
+
signature_consumed=True,
|
|
116
|
+
)
|
|
117
|
+
)
|
|
118
|
+
else:
|
|
119
|
+
# Tool parsing disabled - emit as text
|
|
120
|
+
self.context.append_text_segment(self._signature_buffer)
|
|
121
|
+
self.context.transition_to(TextState(self.context))
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
if match == 'no_match':
|
|
125
|
+
# Not a tool call - emit as text
|
|
126
|
+
self.context.append_text_segment(self._signature_buffer)
|
|
127
|
+
self.context.transition_to(TextState(self.context))
|
|
128
|
+
return
|
|
129
|
+
|
|
130
|
+
# 'partial' - continue buffering
|
|
131
|
+
|
|
132
|
+
def finalize(self) -> None:
|
|
133
|
+
"""
|
|
134
|
+
Called when stream ends while checking JSON signature.
|
|
135
|
+
|
|
136
|
+
Emit buffered content as text.
|
|
137
|
+
"""
|
|
138
|
+
from .text_state import TextState
|
|
139
|
+
|
|
140
|
+
if self._signature_buffer:
|
|
141
|
+
self.context.append_text_segment(self._signature_buffer)
|
|
142
|
+
self._signature_buffer = ""
|
|
143
|
+
|
|
144
|
+
self.context.transition_to(TextState(self.context))
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"""
|
|
2
|
+
JsonToolParsingState: Streams JSON tool call content.
|
|
3
|
+
|
|
4
|
+
This state identifies JSON tool-call boundaries and streams raw JSON content.
|
|
5
|
+
Tool arguments are parsed later by the ToolInvocationAdapter.
|
|
6
|
+
"""
|
|
7
|
+
from typing import TYPE_CHECKING, List
|
|
8
|
+
|
|
9
|
+
from .base_state import BaseState
|
|
10
|
+
from ..events import SegmentType
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from ..parser_context import ParserContext
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JsonToolParsingState(BaseState):
|
|
17
|
+
"""
|
|
18
|
+
Streams JSON tool call content.
|
|
19
|
+
|
|
20
|
+
Expected formats:
|
|
21
|
+
- {"name": "tool_name", "arguments": {...}}
|
|
22
|
+
- [{"name": "tool_name", "arguments": {...}}]
|
|
23
|
+
|
|
24
|
+
Handles nested braces and proper JSON boundary detection.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
context: "ParserContext",
|
|
30
|
+
signature_buffer: str,
|
|
31
|
+
signature_consumed: bool = False,
|
|
32
|
+
):
|
|
33
|
+
super().__init__(context)
|
|
34
|
+
self._signature_buffer = signature_buffer
|
|
35
|
+
self._signature_consumed = signature_consumed
|
|
36
|
+
self._brace_count = 0
|
|
37
|
+
self._bracket_count = 0
|
|
38
|
+
self._in_string = False
|
|
39
|
+
self._escape_next = False
|
|
40
|
+
self._segment_started = False
|
|
41
|
+
self._initialized = False
|
|
42
|
+
self._is_array = signature_buffer.startswith('[')
|
|
43
|
+
|
|
44
|
+
def run(self) -> None:
|
|
45
|
+
"""
|
|
46
|
+
Parse JSON tool content, tracking nested braces.
|
|
47
|
+
"""
|
|
48
|
+
from .text_state import TextState
|
|
49
|
+
|
|
50
|
+
if not self._segment_started:
|
|
51
|
+
self.context.emit_segment_start(SegmentType.TOOL_CALL)
|
|
52
|
+
self._segment_started = True
|
|
53
|
+
|
|
54
|
+
consumed: List[str] = []
|
|
55
|
+
|
|
56
|
+
if not self._initialized:
|
|
57
|
+
if self._signature_consumed:
|
|
58
|
+
consumed.append(self._signature_buffer)
|
|
59
|
+
for char in self._signature_buffer:
|
|
60
|
+
self._update_brace_count(char)
|
|
61
|
+
else:
|
|
62
|
+
signature = self.context.consume(len(self._signature_buffer))
|
|
63
|
+
if signature:
|
|
64
|
+
consumed.append(signature)
|
|
65
|
+
for char in signature:
|
|
66
|
+
self._update_brace_count(char)
|
|
67
|
+
self._initialized = True
|
|
68
|
+
|
|
69
|
+
while self.context.has_more_chars():
|
|
70
|
+
char = self.context.peek_char()
|
|
71
|
+
self.context.advance()
|
|
72
|
+
consumed.append(char)
|
|
73
|
+
self._update_brace_count(char)
|
|
74
|
+
|
|
75
|
+
if self._is_json_complete():
|
|
76
|
+
if consumed:
|
|
77
|
+
self.context.emit_segment_content("".join(consumed))
|
|
78
|
+
|
|
79
|
+
self.context.emit_segment_end()
|
|
80
|
+
self.context.transition_to(TextState(self.context))
|
|
81
|
+
return
|
|
82
|
+
|
|
83
|
+
if consumed:
|
|
84
|
+
self.context.emit_segment_content("".join(consumed))
|
|
85
|
+
|
|
86
|
+
def _update_brace_count(self, char: str) -> None:
|
|
87
|
+
"""Update brace/bracket count, handling strings."""
|
|
88
|
+
if self._escape_next:
|
|
89
|
+
self._escape_next = False
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
if char == '\\' and self._in_string:
|
|
93
|
+
self._escape_next = True
|
|
94
|
+
return
|
|
95
|
+
|
|
96
|
+
if char == '"' and not self._escape_next:
|
|
97
|
+
self._in_string = not self._in_string
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
if self._in_string:
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
if char == '{':
|
|
104
|
+
self._brace_count += 1
|
|
105
|
+
elif char == '}':
|
|
106
|
+
self._brace_count -= 1
|
|
107
|
+
elif char == '[':
|
|
108
|
+
self._bracket_count += 1
|
|
109
|
+
elif char == ']':
|
|
110
|
+
self._bracket_count -= 1
|
|
111
|
+
|
|
112
|
+
def _is_json_complete(self) -> bool:
|
|
113
|
+
"""Check if we have a complete JSON structure."""
|
|
114
|
+
if self._in_string:
|
|
115
|
+
return False
|
|
116
|
+
|
|
117
|
+
if self._is_array:
|
|
118
|
+
return self._bracket_count == 0 and self._brace_count == 0
|
|
119
|
+
else:
|
|
120
|
+
return self._brace_count == 0
|
|
121
|
+
|
|
122
|
+
def finalize(self) -> None:
|
|
123
|
+
"""
|
|
124
|
+
Called when stream ends while parsing JSON.
|
|
125
|
+
|
|
126
|
+
Emit any remaining content and close the segment.
|
|
127
|
+
"""
|
|
128
|
+
from .text_state import TextState
|
|
129
|
+
|
|
130
|
+
if self.context.has_more_chars():
|
|
131
|
+
remaining = self.context.consume_remaining()
|
|
132
|
+
if remaining:
|
|
133
|
+
self.context.emit_segment_content(remaining)
|
|
134
|
+
|
|
135
|
+
if self._segment_started:
|
|
136
|
+
self.context.emit_segment_end()
|
|
137
|
+
self.context.transition_to(TextState(self.context))
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SentinelContentState: Parses sentinel-delimited content blocks.
|
|
3
|
+
"""
|
|
4
|
+
from typing import TYPE_CHECKING, Dict
|
|
5
|
+
|
|
6
|
+
from .delimited_content_state import DelimitedContentState
|
|
7
|
+
from ..sentinel_format import END_MARKER
|
|
8
|
+
from ..events import SegmentType
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..parser_context import ParserContext
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SentinelContentState(DelimitedContentState):
|
|
15
|
+
"""
|
|
16
|
+
Parses content for a sentinel block until the matching end marker.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self,
|
|
21
|
+
context: "ParserContext",
|
|
22
|
+
segment_type: SegmentType,
|
|
23
|
+
metadata: Dict[str, object],
|
|
24
|
+
):
|
|
25
|
+
self.SEGMENT_TYPE = segment_type
|
|
26
|
+
self._metadata = metadata
|
|
27
|
+
super().__init__(context, opening_tag="", closing_tag_override=END_MARKER)
|
|
28
|
+
|
|
29
|
+
def _get_start_metadata(self) -> dict:
|
|
30
|
+
return self._metadata
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SentinelInitializationState: Parses sentinel start headers.
|
|
3
|
+
"""
|
|
4
|
+
import json
|
|
5
|
+
from typing import TYPE_CHECKING, Dict, Optional
|
|
6
|
+
|
|
7
|
+
from .base_state import BaseState
|
|
8
|
+
from ..events import SegmentType
|
|
9
|
+
from ..sentinel_format import START_MARKER, MARKER_END
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from ..parser_context import ParserContext
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SentinelInitializationState(BaseState):
|
|
16
|
+
"""
|
|
17
|
+
Parses the sentinel start header and transitions to content state.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
def __init__(self, context: "ParserContext"):
|
|
21
|
+
super().__init__(context)
|
|
22
|
+
self._header_buffer = ""
|
|
23
|
+
|
|
24
|
+
def run(self) -> None:
|
|
25
|
+
from .text_state import TextState
|
|
26
|
+
from .sentinel_content_state import SentinelContentState
|
|
27
|
+
|
|
28
|
+
if not self.context.has_more_chars():
|
|
29
|
+
return
|
|
30
|
+
|
|
31
|
+
start_pos = self.context.get_position()
|
|
32
|
+
end_idx = self.context.find(MARKER_END, start_pos)
|
|
33
|
+
|
|
34
|
+
if end_idx == -1:
|
|
35
|
+
self._header_buffer += self.context.consume_remaining()
|
|
36
|
+
if not self._is_possible_prefix(self._header_buffer):
|
|
37
|
+
self.context.append_text_segment(self._header_buffer)
|
|
38
|
+
self.context.transition_to(TextState(self.context))
|
|
39
|
+
return
|
|
40
|
+
|
|
41
|
+
self._header_buffer += self.context.consume(end_idx - start_pos + len(MARKER_END))
|
|
42
|
+
|
|
43
|
+
if not self._header_buffer.startswith(START_MARKER):
|
|
44
|
+
self.context.append_text_segment(self._header_buffer)
|
|
45
|
+
self.context.transition_to(TextState(self.context))
|
|
46
|
+
return
|
|
47
|
+
|
|
48
|
+
header_json = self._header_buffer[len(START_MARKER):]
|
|
49
|
+
if header_json.endswith(MARKER_END):
|
|
50
|
+
header_json = header_json[:-len(MARKER_END)]
|
|
51
|
+
header_json = header_json.strip()
|
|
52
|
+
|
|
53
|
+
if not header_json:
|
|
54
|
+
self.context.append_text_segment(self._header_buffer)
|
|
55
|
+
self.context.transition_to(TextState(self.context))
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
data = self._parse_header_json(header_json)
|
|
59
|
+
if not data:
|
|
60
|
+
self.context.append_text_segment(self._header_buffer)
|
|
61
|
+
self.context.transition_to(TextState(self.context))
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
type_str = data.get("type")
|
|
65
|
+
segment_type = self._map_segment_type(type_str)
|
|
66
|
+
|
|
67
|
+
if segment_type is None:
|
|
68
|
+
self.context.append_text_segment(self._header_buffer)
|
|
69
|
+
self.context.transition_to(TextState(self.context))
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
metadata = dict(data)
|
|
73
|
+
metadata.pop("type", None)
|
|
74
|
+
|
|
75
|
+
if self.context.get_current_segment_type() == SegmentType.TEXT:
|
|
76
|
+
self.context.emit_segment_end()
|
|
77
|
+
|
|
78
|
+
self.context.transition_to(
|
|
79
|
+
SentinelContentState(
|
|
80
|
+
self.context,
|
|
81
|
+
segment_type=segment_type,
|
|
82
|
+
metadata=metadata,
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def finalize(self) -> None:
|
|
87
|
+
from .text_state import TextState
|
|
88
|
+
|
|
89
|
+
if self.context.has_more_chars():
|
|
90
|
+
self._header_buffer += self.context.consume_remaining()
|
|
91
|
+
|
|
92
|
+
if self._header_buffer:
|
|
93
|
+
self.context.append_text_segment(self._header_buffer)
|
|
94
|
+
self.context.transition_to(TextState(self.context))
|
|
95
|
+
|
|
96
|
+
def _is_possible_prefix(self, buffer: str) -> bool:
|
|
97
|
+
return START_MARKER.startswith(buffer) or buffer.startswith(START_MARKER)
|
|
98
|
+
|
|
99
|
+
def _parse_header_json(self, header_json: str) -> Optional[Dict[str, object]]:
|
|
100
|
+
try:
|
|
101
|
+
data = json.loads(header_json)
|
|
102
|
+
return data if isinstance(data, dict) else None
|
|
103
|
+
except json.JSONDecodeError:
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
def _map_segment_type(self, type_str: Optional[str]) -> Optional[SegmentType]:
|
|
107
|
+
if not type_str:
|
|
108
|
+
return None
|
|
109
|
+
value = type_str.strip().lower()
|
|
110
|
+
mapping = {
|
|
111
|
+
"text": SegmentType.TEXT,
|
|
112
|
+
"tool": SegmentType.TOOL_CALL,
|
|
113
|
+
"tool_call": SegmentType.TOOL_CALL,
|
|
114
|
+
"write_file": SegmentType.WRITE_FILE,
|
|
115
|
+
"run_bash": SegmentType.RUN_BASH,
|
|
116
|
+
}
|
|
117
|
+
return mapping.get(value)
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TextState: Default state for parsing plain text.
|
|
3
|
+
|
|
4
|
+
This state consumes characters as text content and detects triggers
|
|
5
|
+
for transitioning to specialized parsing states (XML tags, JSON).
|
|
6
|
+
"""
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from .base_state import BaseState
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from ..parser_context import ParserContext
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class TextState(BaseState):
|
|
15
|
+
"""
|
|
16
|
+
Default state for parsing plain text content.
|
|
17
|
+
|
|
18
|
+
This state:
|
|
19
|
+
- Accumulates text characters
|
|
20
|
+
- Detects '<' for potential XML tag transitions
|
|
21
|
+
- Detects '{' or '[' for potential JSON transitions (if enabled)
|
|
22
|
+
- Emits text segments when transitioning or at end of buffer
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, context: "ParserContext"):
|
|
26
|
+
super().__init__(context)
|
|
27
|
+
|
|
28
|
+
def run(self) -> None:
|
|
29
|
+
"""
|
|
30
|
+
Process characters as text until a trigger is found or buffer is exhausted.
|
|
31
|
+
"""
|
|
32
|
+
# Import here to avoid circular dependency
|
|
33
|
+
from .xml_tag_initialization_state import XmlTagInitializationState
|
|
34
|
+
|
|
35
|
+
start_pos = self.context.get_position()
|
|
36
|
+
|
|
37
|
+
if not self.context.has_more_chars():
|
|
38
|
+
return
|
|
39
|
+
|
|
40
|
+
strategies = self.context.detection_strategies
|
|
41
|
+
|
|
42
|
+
best_idx = -1
|
|
43
|
+
best_strategy = None
|
|
44
|
+
for strategy in strategies:
|
|
45
|
+
idx = strategy.next_marker(self.context, start_pos)
|
|
46
|
+
if idx == -1:
|
|
47
|
+
continue
|
|
48
|
+
if best_idx == -1 or idx < best_idx:
|
|
49
|
+
best_idx = idx
|
|
50
|
+
best_strategy = strategy
|
|
51
|
+
|
|
52
|
+
if best_idx == -1:
|
|
53
|
+
text = self.context.substring(start_pos)
|
|
54
|
+
if text:
|
|
55
|
+
self.context.append_text_segment(text)
|
|
56
|
+
self.context.set_position(self.context.get_buffer_length())
|
|
57
|
+
return
|
|
58
|
+
|
|
59
|
+
if best_idx > start_pos:
|
|
60
|
+
text = self.context.substring(start_pos, best_idx)
|
|
61
|
+
if text:
|
|
62
|
+
self.context.append_text_segment(text)
|
|
63
|
+
|
|
64
|
+
self.context.set_position(best_idx)
|
|
65
|
+
|
|
66
|
+
if best_strategy is None:
|
|
67
|
+
self.context.transition_to(XmlTagInitializationState(self.context))
|
|
68
|
+
else:
|
|
69
|
+
self.context.transition_to(best_strategy.create_state(self.context))
|
|
70
|
+
|
|
71
|
+
def finalize(self) -> None:
|
|
72
|
+
"""
|
|
73
|
+
Called when stream ends while in TextState.
|
|
74
|
+
|
|
75
|
+
Nothing special to do here since run() already emits text
|
|
76
|
+
when buffer is exhausted.
|
|
77
|
+
"""
|
|
78
|
+
pass
|