autobyteus 1.0.5__py3-none-any.whl → 1.1.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 +97 -222
- autobyteus/agent/bootstrap_steps/__init__.py +19 -0
- autobyteus/agent/bootstrap_steps/agent_bootstrapper.py +88 -0
- autobyteus/agent/bootstrap_steps/agent_runtime_queue_initialization_step.py +57 -0
- autobyteus/agent/bootstrap_steps/base_bootstrap_step.py +38 -0
- autobyteus/agent/bootstrap_steps/system_prompt_processing_step.py +93 -0
- autobyteus/agent/bootstrap_steps/workspace_context_initialization_step.py +47 -0
- autobyteus/agent/context/__init__.py +18 -0
- autobyteus/agent/context/agent_config.py +80 -0
- autobyteus/agent/context/agent_context.py +132 -0
- autobyteus/agent/context/agent_phase_manager.py +164 -0
- autobyteus/agent/context/agent_runtime_state.py +89 -0
- autobyteus/agent/context/phases.py +47 -0
- autobyteus/agent/events/__init__.py +63 -0
- autobyteus/agent/events/agent_events.py +147 -0
- autobyteus/agent/events/agent_input_event_queue_manager.py +174 -0
- autobyteus/agent/events/notifiers.py +104 -0
- autobyteus/agent/events/worker_event_dispatcher.py +118 -0
- autobyteus/agent/factory/__init__.py +9 -0
- autobyteus/agent/factory/agent_factory.py +126 -79
- autobyteus/agent/group/agent_group.py +155 -0
- autobyteus/agent/group/agent_group_context.py +81 -0
- autobyteus/agent/handlers/__init__.py +36 -0
- autobyteus/agent/handlers/approved_tool_invocation_event_handler.py +134 -0
- autobyteus/agent/handlers/base_event_handler.py +36 -0
- autobyteus/agent/handlers/event_handler_registry.py +76 -0
- autobyteus/agent/handlers/generic_event_handler.py +46 -0
- autobyteus/agent/handlers/inter_agent_message_event_handler.py +76 -0
- autobyteus/agent/handlers/lifecycle_event_logger.py +64 -0
- autobyteus/agent/handlers/llm_complete_response_received_event_handler.py +136 -0
- autobyteus/agent/handlers/llm_user_message_ready_event_handler.py +140 -0
- autobyteus/agent/handlers/tool_execution_approval_event_handler.py +85 -0
- autobyteus/agent/handlers/tool_invocation_request_event_handler.py +186 -0
- autobyteus/agent/handlers/tool_result_event_handler.py +96 -0
- autobyteus/agent/handlers/user_input_message_event_handler.py +77 -0
- autobyteus/agent/hooks/__init__.py +9 -0
- autobyteus/agent/hooks/base_phase_hook.py +52 -0
- autobyteus/agent/input_processor/__init__.py +18 -0
- autobyteus/agent/input_processor/base_user_input_processor.py +51 -0
- autobyteus/agent/input_processor/content_prefixing_input_processor.py +41 -0
- autobyteus/agent/input_processor/metadata_appending_input_processor.py +34 -0
- autobyteus/agent/input_processor/passthrough_input_processor.py +32 -0
- autobyteus/agent/input_processor/processor_definition.py +42 -0
- autobyteus/agent/input_processor/processor_meta.py +46 -0
- autobyteus/agent/input_processor/processor_registry.py +98 -0
- autobyteus/agent/llm_response_processor/__init__.py +16 -0
- autobyteus/agent/llm_response_processor/base_processor.py +50 -0
- autobyteus/agent/llm_response_processor/processor_definition.py +36 -0
- autobyteus/agent/llm_response_processor/processor_meta.py +37 -0
- autobyteus/agent/llm_response_processor/processor_registry.py +94 -0
- autobyteus/agent/llm_response_processor/provider_aware_tool_usage_processor.py +53 -0
- autobyteus/agent/message/__init__.py +20 -0
- autobyteus/agent/message/agent_input_user_message.py +96 -0
- autobyteus/agent/message/context_file.py +82 -0
- autobyteus/agent/message/context_file_type.py +64 -0
- autobyteus/agent/message/{message.py → inter_agent_message.py} +12 -12
- autobyteus/agent/message/{message_types.py → inter_agent_message_type.py} +8 -6
- autobyteus/agent/message/send_message_to.py +142 -36
- autobyteus/agent/remote_agent.py +240 -5
- autobyteus/agent/runtime/__init__.py +15 -0
- autobyteus/agent/runtime/agent_runtime.py +139 -0
- autobyteus/agent/runtime/agent_thread_pool_manager.py +88 -0
- autobyteus/agent/runtime/agent_worker.py +200 -0
- autobyteus/agent/streaming/__init__.py +15 -0
- autobyteus/agent/streaming/agent_event_stream.py +120 -0
- autobyteus/agent/streaming/queue_streamer.py +58 -0
- autobyteus/agent/streaming/stream_event_payloads.py +156 -0
- autobyteus/agent/streaming/stream_events.py +123 -0
- autobyteus/agent/system_prompt_processor/__init__.py +14 -0
- autobyteus/agent/system_prompt_processor/base_processor.py +45 -0
- autobyteus/agent/system_prompt_processor/processor_definition.py +40 -0
- autobyteus/agent/system_prompt_processor/processor_meta.py +47 -0
- autobyteus/agent/system_prompt_processor/processor_registry.py +119 -0
- autobyteus/agent/system_prompt_processor/tool_manifest_injector_processor.py +65 -0
- autobyteus/agent/tool_invocation.py +28 -5
- autobyteus/agent/utils/__init__.py +9 -0
- autobyteus/agent/utils/wait_for_idle.py +59 -0
- autobyteus/agent/workflow/__init__.py +11 -0
- autobyteus/agent/workflow/agentic_workflow.py +89 -0
- autobyteus/agent/workflow/base_agentic_workflow.py +98 -0
- autobyteus/agent/workspace/__init__.py +9 -0
- autobyteus/agent/workspace/base_workspace.py +55 -0
- autobyteus/cli/__init__.py +10 -0
- autobyteus/cli/agent_cli.py +299 -0
- autobyteus/events/event_emitter.py +33 -56
- autobyteus/events/event_manager.py +133 -66
- autobyteus/events/event_types.py +41 -14
- autobyteus/llm/api/autobyteus_llm.py +13 -15
- autobyteus/llm/api/bedrock_llm.py +9 -3
- autobyteus/llm/api/claude_llm.py +10 -5
- autobyteus/llm/api/deepseek_llm.py +53 -91
- autobyteus/llm/api/gemini_llm.py +10 -4
- autobyteus/llm/api/grok_llm.py +53 -77
- autobyteus/llm/api/groq_llm.py +10 -5
- autobyteus/llm/api/mistral_llm.py +10 -5
- autobyteus/llm/api/nvidia_llm.py +9 -4
- autobyteus/llm/api/ollama_llm.py +56 -48
- autobyteus/llm/api/openai_llm.py +20 -14
- autobyteus/llm/base_llm.py +95 -34
- autobyteus/llm/extensions/base_extension.py +3 -4
- autobyteus/llm/extensions/token_usage_tracking_extension.py +2 -3
- autobyteus/llm/llm_factory.py +12 -13
- autobyteus/llm/models.py +87 -8
- autobyteus/llm/user_message.py +73 -0
- autobyteus/llm/utils/llm_config.py +124 -27
- autobyteus/llm/utils/response_types.py +3 -2
- autobyteus/llm/utils/token_usage.py +7 -4
- autobyteus/rpc/__init__.py +73 -0
- autobyteus/rpc/client/__init__.py +17 -0
- autobyteus/rpc/client/abstract_client_connection.py +124 -0
- autobyteus/rpc/client/client_connection_manager.py +153 -0
- autobyteus/rpc/client/sse_client_connection.py +306 -0
- autobyteus/rpc/client/stdio_client_connection.py +280 -0
- autobyteus/rpc/config/__init__.py +13 -0
- autobyteus/rpc/config/agent_server_config.py +153 -0
- autobyteus/rpc/config/agent_server_registry.py +152 -0
- autobyteus/rpc/hosting.py +244 -0
- autobyteus/rpc/protocol.py +244 -0
- autobyteus/rpc/server/__init__.py +20 -0
- autobyteus/rpc/server/agent_server_endpoint.py +181 -0
- autobyteus/rpc/server/base_method_handler.py +40 -0
- autobyteus/rpc/server/method_handlers.py +259 -0
- autobyteus/rpc/server/sse_server_handler.py +182 -0
- autobyteus/rpc/server/stdio_server_handler.py +151 -0
- autobyteus/rpc/server_main.py +198 -0
- autobyteus/rpc/transport_type.py +13 -0
- autobyteus/tools/__init__.py +75 -0
- autobyteus/tools/ask_user_input.py +34 -77
- autobyteus/tools/base_tool.py +66 -37
- autobyteus/tools/bash/__init__.py +2 -0
- autobyteus/tools/bash/bash_executor.py +42 -79
- autobyteus/tools/browser/__init__.py +2 -0
- autobyteus/tools/browser/session_aware/browser_session_aware_navigate_to.py +50 -42
- autobyteus/tools/browser/session_aware/browser_session_aware_tool.py +7 -4
- autobyteus/tools/browser/session_aware/browser_session_aware_web_element_trigger.py +117 -125
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_reader.py +75 -22
- autobyteus/tools/browser/session_aware/browser_session_aware_webpage_screenshot_taker.py +94 -28
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_web_element_trigger_factory.py +10 -2
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_reader_factory.py +18 -2
- autobyteus/tools/browser/session_aware/factory/browser_session_aware_webpage_screenshot_taker_factory.py +10 -2
- autobyteus/tools/browser/session_aware/shared_browser_session_manager.py +4 -3
- autobyteus/tools/browser/standalone/__init__.py +7 -0
- autobyteus/tools/browser/standalone/factory/google_search_factory.py +17 -2
- autobyteus/tools/browser/standalone/factory/webpage_reader_factory.py +17 -2
- autobyteus/tools/browser/standalone/factory/webpage_screenshot_taker_factory.py +10 -2
- autobyteus/tools/browser/standalone/google_search_ui.py +104 -67
- autobyteus/tools/browser/standalone/navigate_to.py +52 -28
- autobyteus/tools/browser/standalone/web_page_pdf_generator.py +94 -0
- autobyteus/tools/browser/standalone/webpage_image_downloader.py +146 -61
- autobyteus/tools/browser/standalone/webpage_reader.py +80 -61
- autobyteus/tools/browser/standalone/webpage_screenshot_taker.py +91 -45
- autobyteus/tools/factory/__init__.py +9 -0
- autobyteus/tools/factory/tool_factory.py +25 -4
- autobyteus/tools/file/file_reader.py +22 -51
- autobyteus/tools/file/file_writer.py +25 -56
- autobyteus/tools/functional_tool.py +234 -0
- autobyteus/tools/image_downloader.py +49 -71
- autobyteus/tools/mcp/__init__.py +47 -0
- autobyteus/tools/mcp/call_handlers/__init__.py +18 -0
- autobyteus/tools/mcp/call_handlers/base_handler.py +40 -0
- autobyteus/tools/mcp/call_handlers/sse_handler.py +22 -0
- autobyteus/tools/mcp/call_handlers/stdio_handler.py +62 -0
- autobyteus/tools/mcp/call_handlers/streamable_http_handler.py +55 -0
- autobyteus/tools/mcp/config_service.py +258 -0
- autobyteus/tools/mcp/factory.py +70 -0
- autobyteus/tools/mcp/registrar.py +135 -0
- autobyteus/tools/mcp/schema_mapper.py +131 -0
- autobyteus/tools/mcp/tool.py +101 -0
- autobyteus/tools/mcp/types.py +96 -0
- autobyteus/tools/parameter_schema.py +268 -0
- autobyteus/tools/pdf_downloader.py +78 -79
- autobyteus/tools/registry/__init__.py +0 -2
- autobyteus/tools/registry/tool_definition.py +106 -34
- autobyteus/tools/registry/tool_registry.py +46 -22
- autobyteus/tools/timer.py +150 -102
- autobyteus/tools/tool_config.py +117 -0
- autobyteus/tools/tool_meta.py +48 -26
- autobyteus/tools/usage/__init__.py +6 -0
- autobyteus/tools/usage/formatters/__init__.py +31 -0
- autobyteus/tools/usage/formatters/anthropic_json_example_formatter.py +18 -0
- autobyteus/tools/usage/formatters/anthropic_json_schema_formatter.py +25 -0
- autobyteus/tools/usage/formatters/base_formatter.py +42 -0
- autobyteus/tools/usage/formatters/default_json_example_formatter.py +42 -0
- autobyteus/tools/usage/formatters/default_json_schema_formatter.py +28 -0
- autobyteus/tools/usage/formatters/default_xml_example_formatter.py +55 -0
- autobyteus/tools/usage/formatters/default_xml_schema_formatter.py +46 -0
- autobyteus/tools/usage/formatters/gemini_json_example_formatter.py +34 -0
- autobyteus/tools/usage/formatters/gemini_json_schema_formatter.py +25 -0
- autobyteus/tools/usage/formatters/google_json_example_formatter.py +34 -0
- autobyteus/tools/usage/formatters/google_json_schema_formatter.py +25 -0
- autobyteus/tools/usage/formatters/openai_json_example_formatter.py +49 -0
- autobyteus/tools/usage/formatters/openai_json_schema_formatter.py +28 -0
- autobyteus/tools/usage/parsers/__init__.py +22 -0
- autobyteus/tools/usage/parsers/anthropic_xml_tool_usage_parser.py +10 -0
- autobyteus/tools/usage/parsers/base_parser.py +41 -0
- autobyteus/tools/usage/parsers/default_json_tool_usage_parser.py +106 -0
- autobyteus/tools/usage/parsers/default_xml_tool_usage_parser.py +135 -0
- autobyteus/tools/usage/parsers/exceptions.py +13 -0
- autobyteus/tools/usage/parsers/gemini_json_tool_usage_parser.py +68 -0
- autobyteus/tools/usage/parsers/openai_json_tool_usage_parser.py +147 -0
- autobyteus/tools/usage/parsers/provider_aware_tool_usage_parser.py +67 -0
- autobyteus/tools/usage/providers/__init__.py +22 -0
- autobyteus/tools/usage/providers/json_example_provider.py +32 -0
- autobyteus/tools/usage/providers/json_schema_provider.py +35 -0
- autobyteus/tools/usage/providers/json_tool_usage_parser_provider.py +28 -0
- autobyteus/tools/usage/providers/tool_manifest_provider.py +68 -0
- autobyteus/tools/usage/providers/xml_example_provider.py +28 -0
- autobyteus/tools/usage/providers/xml_schema_provider.py +29 -0
- autobyteus/tools/usage/providers/xml_tool_usage_parser_provider.py +26 -0
- autobyteus/tools/usage/registries/__init__.py +20 -0
- autobyteus/tools/usage/registries/json_example_formatter_registry.py +51 -0
- autobyteus/tools/usage/registries/json_schema_formatter_registry.py +51 -0
- autobyteus/tools/usage/registries/json_tool_usage_parser_registry.py +42 -0
- autobyteus/tools/usage/registries/xml_example_formatter_registry.py +30 -0
- autobyteus/tools/usage/registries/xml_schema_formatter_registry.py +33 -0
- autobyteus/tools/usage/registries/xml_tool_usage_parser_registry.py +30 -0
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/METADATA +21 -3
- autobyteus-1.1.0.dist-info/RECORD +279 -0
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/WHEEL +1 -1
- autobyteus/agent/async_agent.py +0 -175
- autobyteus/agent/async_group_aware_agent.py +0 -136
- autobyteus/agent/group/async_group_aware_agent.py +0 -122
- autobyteus/agent/group/coordinator_agent.py +0 -36
- autobyteus/agent/group/group_aware_agent.py +0 -121
- autobyteus/agent/orchestrator/__init__.py +0 -0
- autobyteus/agent/orchestrator/base_agent_orchestrator.py +0 -82
- autobyteus/agent/orchestrator/multi_replica_agent_orchestrator.py +0 -72
- autobyteus/agent/orchestrator/single_replica_agent_orchestrator.py +0 -43
- autobyteus/agent/registry/__init__.py +0 -11
- autobyteus/agent/registry/agent_definition.py +0 -94
- autobyteus/agent/registry/agent_registry.py +0 -114
- autobyteus/agent/response_parser/__init__.py +0 -0
- autobyteus/agent/response_parser/tool_usage_command_parser.py +0 -100
- autobyteus/agent/status.py +0 -12
- autobyteus/conversation/__init__.py +0 -0
- autobyteus/conversation/conversation.py +0 -54
- autobyteus/conversation/user_message.py +0 -59
- autobyteus/events/decorators.py +0 -29
- autobyteus/prompt/prompt_version_manager.py +0 -58
- autobyteus/prompt/storage/__init__.py +0 -0
- autobyteus/prompt/storage/prompt_version_model.py +0 -29
- autobyteus/prompt/storage/prompt_version_repository.py +0 -83
- autobyteus/tools/bash/factory/__init__.py +0 -0
- autobyteus/tools/bash/factory/bash_executor_factory.py +0 -6
- autobyteus/tools/factory/ask_user_input_factory.py +0 -6
- autobyteus/tools/factory/image_downloader_factory.py +0 -9
- autobyteus/tools/factory/pdf_downloader_factory.py +0 -9
- autobyteus/tools/factory/webpage_image_downloader_factory.py +0 -6
- autobyteus/tools/file/factory/__init__.py +0 -0
- autobyteus/tools/file/factory/file_reader_factory.py +0 -6
- autobyteus/tools/file/factory/file_writer_factory.py +0 -6
- autobyteus/tools/mcp_remote_tool.py +0 -82
- autobyteus/tools/web_page_pdf_generator.py +0 -90
- autobyteus-1.0.5.dist-info/RECORD +0 -163
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/licenses/LICENSE +0 -0
- {autobyteus-1.0.5.dist-info → autobyteus-1.1.0.dist-info}/top_level.txt +0 -0
|
@@ -1,89 +1,88 @@
|
|
|
1
|
-
#
|
|
2
|
-
|
|
1
|
+
# This was top-level, keep it there.
|
|
3
2
|
import os
|
|
4
|
-
import requests
|
|
5
3
|
import logging
|
|
4
|
+
import asyncio
|
|
5
|
+
import requests
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from
|
|
8
|
-
from autobyteus.utils.file_utils import get_default_download_folder
|
|
9
|
-
|
|
10
|
-
class PDFDownloader(BaseTool):
|
|
11
|
-
"""
|
|
12
|
-
A tool that downloads a PDF file from a given URL and saves it locally.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def __init__(self, custom_download_folder=None):
|
|
16
|
-
super().__init__()
|
|
17
|
-
self.logger = logging.getLogger(__name__)
|
|
18
|
-
self.default_download_folder = get_default_download_folder()
|
|
19
|
-
self.download_folder = custom_download_folder or self.default_download_folder
|
|
20
|
-
|
|
21
|
-
@classmethod
|
|
22
|
-
def tool_usage_xml(cls):
|
|
23
|
-
"""
|
|
24
|
-
Return an XML string describing the usage of the PDFDownloader tool.
|
|
25
|
-
|
|
26
|
-
Returns:
|
|
27
|
-
str: An XML description of how to use the PDFDownloader tool.
|
|
28
|
-
"""
|
|
29
|
-
return '''PDFDownloader: Downloads a PDF file from a given URL. Usage:
|
|
30
|
-
<command name="PDFDownloader">
|
|
31
|
-
<arg name="url">https://example.com/file.pdf</arg>
|
|
32
|
-
</command>
|
|
33
|
-
'''
|
|
34
|
-
|
|
35
|
-
def _execute(self, **kwargs):
|
|
36
|
-
"""
|
|
37
|
-
Download a PDF file from the given URL and save it locally.
|
|
7
|
+
from typing import TYPE_CHECKING, Optional
|
|
38
8
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
'url': The URL of the PDF file to download.
|
|
42
|
-
'folder' (optional): Custom download folder path.
|
|
43
|
-
|
|
44
|
-
Returns:
|
|
45
|
-
str: A message indicating the result of the download operation.
|
|
46
|
-
|
|
47
|
-
Raises:
|
|
48
|
-
ValueError: If the 'url' keyword argument is not specified.
|
|
49
|
-
"""
|
|
50
|
-
url = kwargs.get('url')
|
|
51
|
-
custom_folder = kwargs.get('folder')
|
|
52
|
-
download_folder = custom_folder or self.download_folder
|
|
53
|
-
|
|
54
|
-
if not url:
|
|
55
|
-
raise ValueError("The 'url' keyword argument must be specified.")
|
|
56
|
-
|
|
57
|
-
self.logger.info(f"Attempting to download PDF from {url}")
|
|
9
|
+
from autobyteus.tools import tool
|
|
10
|
+
from autobyteus.utils.file_utils import get_default_download_folder
|
|
58
11
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
response.raise_for_status()
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from autobyteus.agent.context import AgentContext
|
|
62
14
|
|
|
63
|
-
|
|
64
|
-
if 'application/pdf' not in content_type:
|
|
65
|
-
raise ValueError(f"The URL does not point to a PDF file. Content-Type: {content_type}")
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
66
16
|
|
|
67
|
-
|
|
17
|
+
@tool(name="PDFDownloader")
|
|
18
|
+
async def pdf_downloader( # function name can be pdf_downloader
|
|
19
|
+
context: 'AgentContext',
|
|
20
|
+
url: str,
|
|
21
|
+
folder: Optional[str] = None
|
|
22
|
+
) -> str:
|
|
23
|
+
"""
|
|
24
|
+
Downloads a PDF file from a given URL and saves it locally.
|
|
25
|
+
'url' is the URL of the PDF.
|
|
26
|
+
'folder' (optional) is a custom directory to save the PDF. If not given,
|
|
27
|
+
uses the system's default download folder. Validates Content-Type.
|
|
28
|
+
"""
|
|
29
|
+
logger.debug(f"Functional PDFDownloader tool for agent {context.agent_id}, URL: {url}, Folder: {folder}")
|
|
30
|
+
|
|
31
|
+
current_download_folder = folder if folder else get_default_download_folder()
|
|
32
|
+
|
|
33
|
+
try:
|
|
34
|
+
loop = asyncio.get_event_loop()
|
|
35
|
+
response = await loop.run_in_executor(None, lambda: requests.get(url, stream=True, timeout=30))
|
|
36
|
+
response.raise_for_status()
|
|
37
|
+
|
|
38
|
+
content_type = response.headers.get('Content-Type', '').lower()
|
|
39
|
+
if 'application/pdf' not in content_type:
|
|
40
|
+
response.close()
|
|
41
|
+
raise ValueError(f"The URL does not point to a PDF file. Content-Type: {content_type}")
|
|
42
|
+
|
|
43
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
|
44
|
+
filename_from_header = None
|
|
45
|
+
if 'Content-Disposition' in response.headers:
|
|
46
|
+
import re
|
|
47
|
+
match = re.search(r'filename=[\'"]?([^\'"\s]+)[\'"]?', response.headers['Content-Disposition'])
|
|
48
|
+
if match: filename_from_header = match.group(1)
|
|
49
|
+
|
|
50
|
+
if filename_from_header and filename_from_header.lower().endswith(".pdf"):
|
|
51
|
+
import string
|
|
52
|
+
valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits)
|
|
53
|
+
filename_from_header = ''.join(c for c in filename_from_header if c in valid_chars)[:200]
|
|
54
|
+
filename = f"{timestamp}_{filename_from_header}"
|
|
55
|
+
else:
|
|
68
56
|
filename = f"downloaded_pdf_{timestamp}.pdf"
|
|
69
|
-
save_path = os.path.join(download_folder, filename)
|
|
70
57
|
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
save_path = os.path.join(current_download_folder, filename)
|
|
59
|
+
os.makedirs(current_download_folder, exist_ok=True)
|
|
60
|
+
|
|
61
|
+
def download_and_save_sync():
|
|
62
|
+
with open(save_path, 'wb') as file_handle:
|
|
73
63
|
for chunk in response.iter_content(chunk_size=8192):
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
64
|
+
file_handle.write(chunk)
|
|
65
|
+
response.close()
|
|
66
|
+
|
|
67
|
+
await loop.run_in_executor(None, download_and_save_sync)
|
|
68
|
+
|
|
69
|
+
logger.info(f"PDF successfully downloaded and saved to {save_path}")
|
|
70
|
+
return f"PDF successfully downloaded and saved to {save_path}"
|
|
71
|
+
except requests.exceptions.Timeout:
|
|
72
|
+
logger.error(f"Timeout downloading PDF from {url}", exc_info=True)
|
|
73
|
+
return f"Error downloading PDF: Timeout occurred for URL {url}"
|
|
74
|
+
except requests.exceptions.RequestException as e:
|
|
75
|
+
logger.error(f"Error downloading PDF from {url}: {str(e)}", exc_info=True)
|
|
76
|
+
return f"Error downloading PDF: {str(e)}"
|
|
77
|
+
except ValueError as e:
|
|
78
|
+
logger.error(f"Content type error for PDF from {url}: {str(e)}", exc_info=True)
|
|
79
|
+
return str(e)
|
|
80
|
+
except IOError as e:
|
|
81
|
+
logger.error(f"Error saving PDF to {current_download_folder}: {str(e)}", exc_info=True)
|
|
82
|
+
return f"Error saving PDF: {str(e)}"
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.error(f"Unexpected error downloading PDF from {url}: {str(e)}", exc_info=True)
|
|
85
|
+
return f"An unexpected error occurred: {str(e)}"
|
|
86
|
+
finally:
|
|
87
|
+
if 'response' in locals() and hasattr(response, 'close') and response.raw and not response.raw.closed:
|
|
88
|
+
response.close()
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
# file: autobyteus/autobyteus/tools/registry/__init__.py
|
|
2
2
|
from .tool_definition import ToolDefinition
|
|
3
3
|
from .tool_registry import ToolRegistry, default_tool_registry
|
|
4
|
-
from autobyteus.tools.factory.tool_factory import ToolFactory
|
|
5
4
|
|
|
6
5
|
__all__ = [
|
|
7
6
|
"ToolDefinition",
|
|
8
7
|
"ToolRegistry",
|
|
9
8
|
"default_tool_registry",
|
|
10
|
-
"ToolFactory"
|
|
11
9
|
]
|
|
@@ -1,60 +1,132 @@
|
|
|
1
|
-
# file: autobyteus/tools/registry/tool_definition.py
|
|
1
|
+
# file: autobyteus/autobyteus/tools/registry/tool_definition.py
|
|
2
2
|
import logging
|
|
3
|
-
|
|
3
|
+
import json
|
|
4
|
+
from typing import Dict, Any, List as TypingList, Type, TYPE_CHECKING, Optional, Callable
|
|
5
|
+
|
|
6
|
+
from autobyteus.llm.providers import LLMProvider
|
|
7
|
+
from autobyteus.tools.tool_config import ToolConfig
|
|
8
|
+
from autobyteus.tools.parameter_schema import ParameterSchema
|
|
9
|
+
from autobyteus.tools.usage.providers import (
|
|
10
|
+
XmlSchemaProvider,
|
|
11
|
+
JsonSchemaProvider,
|
|
12
|
+
XmlExampleProvider,
|
|
13
|
+
JsonExampleProvider
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from autobyteus.tools.base_tool import BaseTool
|
|
4
18
|
|
|
5
19
|
logger = logging.getLogger(__name__)
|
|
6
20
|
|
|
7
21
|
class ToolDefinition:
|
|
8
22
|
"""
|
|
9
|
-
Represents the
|
|
10
|
-
|
|
23
|
+
Represents the definition of a tool, containing its metadata and the means
|
|
24
|
+
to create an instance. It can generate provider-specific usage information on demand.
|
|
11
25
|
"""
|
|
12
26
|
def __init__(self,
|
|
13
27
|
name: str,
|
|
14
|
-
description: str
|
|
28
|
+
description: str,
|
|
29
|
+
argument_schema: Optional['ParameterSchema'],
|
|
30
|
+
config_schema: Optional['ParameterSchema'] = None,
|
|
31
|
+
tool_class: Optional[Type['BaseTool']] = None,
|
|
32
|
+
custom_factory: Optional[Callable[['ToolConfig'], 'BaseTool']] = None):
|
|
15
33
|
"""
|
|
16
34
|
Initializes the ToolDefinition.
|
|
17
|
-
|
|
18
|
-
Args:
|
|
19
|
-
name: The unique name/identifier of the tool.
|
|
20
|
-
description: The static usage description string for the tool (e.g., XML usage format).
|
|
21
|
-
|
|
22
|
-
Raises:
|
|
23
|
-
ValueError: If name or description are empty or invalid.
|
|
24
35
|
"""
|
|
25
36
|
if not name or not isinstance(name, str):
|
|
26
37
|
raise ValueError("ToolDefinition requires a non-empty string 'name'.")
|
|
27
38
|
if not description or not isinstance(description, str):
|
|
28
39
|
raise ValueError(f"ToolDefinition '{name}' requires a non-empty string 'description'.")
|
|
29
40
|
|
|
41
|
+
if tool_class is None and custom_factory is None:
|
|
42
|
+
raise ValueError(f"ToolDefinition '{name}' must provide either a 'tool_class' or a 'custom_factory'.")
|
|
43
|
+
if tool_class is not None and custom_factory is not None:
|
|
44
|
+
raise ValueError(f"ToolDefinition '{name}' cannot have both a 'tool_class' and a 'custom_factory'.")
|
|
45
|
+
|
|
46
|
+
if tool_class and not isinstance(tool_class, type):
|
|
47
|
+
raise TypeError(f"ToolDefinition '{name}' requires a valid class for 'tool_class'.")
|
|
48
|
+
if custom_factory and not callable(custom_factory):
|
|
49
|
+
raise TypeError(f"ToolDefinition '{name}' requires a callable for 'custom_factory'.")
|
|
50
|
+
|
|
51
|
+
if argument_schema is not None and not isinstance(argument_schema, ParameterSchema):
|
|
52
|
+
raise TypeError(f"ToolDefinition '{name}' received an invalid 'argument_schema'. Expected ParameterSchema or None.")
|
|
53
|
+
if config_schema is not None and not isinstance(config_schema, ParameterSchema):
|
|
54
|
+
raise TypeError(f"ToolDefinition '{name}' received an invalid 'config_schema'. Expected ParameterSchema or None.")
|
|
55
|
+
|
|
30
56
|
self._name = name
|
|
31
57
|
self._description = description
|
|
32
|
-
|
|
58
|
+
self._argument_schema: Optional['ParameterSchema'] = argument_schema
|
|
59
|
+
self._config_schema: Optional['ParameterSchema'] = config_schema
|
|
60
|
+
self._tool_class = tool_class
|
|
61
|
+
self._custom_factory = custom_factory
|
|
62
|
+
|
|
33
63
|
logger.debug(f"ToolDefinition created for tool '{self.name}'.")
|
|
34
64
|
|
|
65
|
+
# --- Properties ---
|
|
66
|
+
@property
|
|
67
|
+
def name(self) -> str: return self._name
|
|
68
|
+
@property
|
|
69
|
+
def description(self) -> str: return self._description
|
|
70
|
+
@property
|
|
71
|
+
def tool_class(self) -> Optional[Type['BaseTool']]: return self._tool_class
|
|
35
72
|
@property
|
|
36
|
-
def
|
|
37
|
-
|
|
38
|
-
|
|
73
|
+
def custom_factory(self) -> Optional[Callable[['ToolConfig'], 'BaseTool']]: return self._custom_factory
|
|
74
|
+
@property
|
|
75
|
+
def argument_schema(self) -> Optional['ParameterSchema']: return self._argument_schema
|
|
76
|
+
@property
|
|
77
|
+
def config_schema(self) -> Optional['ParameterSchema']: return self._config_schema
|
|
78
|
+
|
|
79
|
+
# --- Schema Generation API ---
|
|
80
|
+
def get_usage_xml(self, provider: Optional[LLMProvider] = None) -> str:
|
|
81
|
+
"""
|
|
82
|
+
Generates the standardized XML usage schema string for this tool.
|
|
83
|
+
The provider argument is included for API consistency and future-proofing.
|
|
84
|
+
"""
|
|
85
|
+
provider_instance = XmlSchemaProvider()
|
|
86
|
+
return provider_instance.provide(self, llm_provider=provider)
|
|
39
87
|
|
|
88
|
+
def get_usage_json(self, provider: Optional[LLMProvider] = None) -> Dict[str, Any]:
|
|
89
|
+
"""
|
|
90
|
+
Generates the usage schema as a dictionary.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
provider: If provided, generates a provider-specific JSON format.
|
|
94
|
+
If None, generates a default, generic JSON format.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
A dictionary representing the tool's usage schema.
|
|
98
|
+
"""
|
|
99
|
+
provider_instance = JsonSchemaProvider()
|
|
100
|
+
return provider_instance.provide(self, llm_provider=provider)
|
|
101
|
+
|
|
102
|
+
# --- Example Generation API ---
|
|
103
|
+
def get_usage_xml_example(self, provider: Optional[LLMProvider] = None) -> str:
|
|
104
|
+
"""
|
|
105
|
+
Generates a standardized XML usage example string for this tool.
|
|
106
|
+
The provider argument is included for API consistency and future-proofing.
|
|
107
|
+
"""
|
|
108
|
+
provider_instance = XmlExampleProvider()
|
|
109
|
+
return provider_instance.provide(self, llm_provider=provider)
|
|
110
|
+
|
|
111
|
+
def get_usage_json_example(self, provider: Optional[LLMProvider] = None) -> Any:
|
|
112
|
+
"""
|
|
113
|
+
Generates a usage example, either as a dict or a string.
|
|
114
|
+
"""
|
|
115
|
+
provider_instance = JsonExampleProvider()
|
|
116
|
+
return provider_instance.provide(self, llm_provider=provider)
|
|
117
|
+
|
|
118
|
+
# --- Other methods ---
|
|
40
119
|
@property
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
return self._description
|
|
120
|
+
def has_instantiation_config(self) -> bool:
|
|
121
|
+
return self._config_schema is not None and len(self._config_schema) > 0
|
|
44
122
|
|
|
45
|
-
def
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
desc_repr = desc_repr.replace('\n', '\\n').replace('\t', '\\t')
|
|
52
|
-
return (f"ToolDefinition(name='{self.name}', description='{desc_repr}')")
|
|
53
|
-
|
|
54
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
55
|
-
"""Returns a dictionary representation of the tool definition."""
|
|
56
|
-
return {
|
|
57
|
-
"name": self.name,
|
|
58
|
-
"description": self.description,
|
|
59
|
-
}
|
|
123
|
+
def validate_instantiation_config(self, config_data: Dict[str, Any]) -> tuple[bool, TypingList[str]]:
|
|
124
|
+
if not self._config_schema:
|
|
125
|
+
if config_data:
|
|
126
|
+
return False, [f"Tool '{self.name}' does not accept instantiation configuration parameters"]
|
|
127
|
+
return True, []
|
|
128
|
+
return self._config_schema.validate_config(config_data)
|
|
60
129
|
|
|
130
|
+
def __repr__(self) -> str:
|
|
131
|
+
creator_repr = f"class='{self._tool_class.__name__}'" if self._tool_class else "factory=True"
|
|
132
|
+
return (f"ToolDefinition(name='{self.name}', {creator_repr})")
|
|
@@ -1,34 +1,32 @@
|
|
|
1
|
-
# file: autobyteus/
|
|
1
|
+
# file: autobyteus/tools/registry/tool_registry.py
|
|
2
2
|
import logging
|
|
3
|
-
from typing import Dict, List, Optional
|
|
3
|
+
from typing import Dict, List, Optional, Type, TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from autobyteus.tools.registry.tool_definition import ToolDefinition
|
|
6
6
|
from autobyteus.utils.singleton import SingletonMeta
|
|
7
|
-
from autobyteus.tools.
|
|
7
|
+
from autobyteus.tools.tool_config import ToolConfig
|
|
8
8
|
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from autobyteus.tools.base_tool import BaseTool
|
|
9
11
|
|
|
10
12
|
logger = logging.getLogger(__name__)
|
|
11
13
|
|
|
12
14
|
class ToolRegistry(metaclass=SingletonMeta):
|
|
13
15
|
"""
|
|
14
|
-
Manages ToolDefinitions
|
|
15
|
-
|
|
16
|
+
Manages ToolDefinitions and creates tool instances. It can create instances
|
|
17
|
+
from a tool_class or by using a custom_factory provided in the definition.
|
|
16
18
|
"""
|
|
17
19
|
_definitions: Dict[str, ToolDefinition] = {}
|
|
18
20
|
|
|
19
|
-
def __init__(self
|
|
21
|
+
def __init__(self):
|
|
20
22
|
"""
|
|
21
|
-
Initializes the ToolRegistry
|
|
22
|
-
|
|
23
|
-
Args:
|
|
24
|
-
tool_factory: The ToolFactory instance used to create tool instances.
|
|
23
|
+
Initializes the ToolRegistry.
|
|
25
24
|
"""
|
|
26
|
-
|
|
27
|
-
logger.info("ToolRegistry initialized with ToolFactory.")
|
|
25
|
+
logger.info("ToolRegistry initialized.")
|
|
28
26
|
|
|
29
27
|
def register_tool(self, definition: ToolDefinition):
|
|
30
28
|
"""
|
|
31
|
-
Registers a tool definition
|
|
29
|
+
Registers a tool definition.
|
|
32
30
|
|
|
33
31
|
Args:
|
|
34
32
|
definition: The ToolDefinition object to register.
|
|
@@ -53,40 +51,66 @@ class ToolRegistry(metaclass=SingletonMeta):
|
|
|
53
51
|
name: The unique name of the tool definition to retrieve.
|
|
54
52
|
|
|
55
53
|
Returns:
|
|
56
|
-
The ToolDefinition object
|
|
54
|
+
The ToolDefinition object if found, otherwise None.
|
|
57
55
|
"""
|
|
58
56
|
definition = self._definitions.get(name)
|
|
59
57
|
if not definition:
|
|
60
58
|
logger.debug(f"Tool definition not found for name: '{name}'")
|
|
61
59
|
return definition
|
|
62
60
|
|
|
63
|
-
def create_tool(self, name: str):
|
|
61
|
+
def create_tool(self, name: str, config: Optional[ToolConfig] = None) -> 'BaseTool':
|
|
64
62
|
"""
|
|
65
|
-
Creates a tool instance using
|
|
63
|
+
Creates a tool instance using its definition, either from a factory or a class.
|
|
66
64
|
|
|
67
65
|
Args:
|
|
68
66
|
name: The name of the tool to create.
|
|
67
|
+
config: Optional ToolConfig with constructor parameters for class-based tools
|
|
68
|
+
or to be passed to a custom factory.
|
|
69
69
|
|
|
70
70
|
Returns:
|
|
71
|
-
The tool instance if the definition exists
|
|
71
|
+
The tool instance if the definition exists.
|
|
72
72
|
|
|
73
73
|
Raises:
|
|
74
|
-
ValueError: If the tool definition is not found.
|
|
74
|
+
ValueError: If the tool definition is not found or is invalid.
|
|
75
|
+
TypeError: If tool instantiation fails.
|
|
75
76
|
"""
|
|
76
77
|
definition = self.get_tool_definition(name)
|
|
77
78
|
if not definition:
|
|
78
79
|
logger.error(f"Cannot create tool: No definition found for name '{name}'")
|
|
79
80
|
raise ValueError(f"No tool definition found for name '{name}'")
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
try:
|
|
83
|
+
# Prefer the custom factory if it exists
|
|
84
|
+
if definition.custom_factory:
|
|
85
|
+
logger.info(f"Creating tool instance for '{name}' using its custom factory.")
|
|
86
|
+
# Pass the config to the factory. The factory can choose to use it or not.
|
|
87
|
+
tool_instance = definition.custom_factory(config)
|
|
88
|
+
|
|
89
|
+
# Fall back to instantiating the tool_class
|
|
90
|
+
elif definition.tool_class:
|
|
91
|
+
# For class-based tools, the convention is to pass the ToolConfig object
|
|
92
|
+
# itself to the constructor under the 'config' keyword argument.
|
|
93
|
+
logger.info(f"Creating tool instance for '{name}' using class '{definition.tool_class.__name__}' and passing ToolConfig.")
|
|
94
|
+
tool_instance = definition.tool_class(config=config)
|
|
95
|
+
|
|
96
|
+
else:
|
|
97
|
+
# This case should be prevented by ToolDefinition's validation
|
|
98
|
+
raise ValueError(f"ToolDefinition for '{name}' is invalid: missing both tool_class and custom_factory.")
|
|
99
|
+
|
|
100
|
+
logger.debug(f"Successfully created tool instance for '{name}'")
|
|
101
|
+
return tool_instance
|
|
102
|
+
|
|
103
|
+
except Exception as e:
|
|
104
|
+
creator_type = "factory" if definition.custom_factory else f"class '{definition.tool_class.__name__}'"
|
|
105
|
+
logger.error(f"Failed to create tool instance for '{name}' using {creator_type}: {e}", exc_info=True)
|
|
106
|
+
raise TypeError(f"Failed to create tool '{name}': {e}") from e
|
|
83
107
|
|
|
84
108
|
def list_tools(self) -> List[ToolDefinition]:
|
|
85
109
|
"""
|
|
86
110
|
Returns a list of all registered tool definitions.
|
|
87
111
|
|
|
88
112
|
Returns:
|
|
89
|
-
A list of ToolDefinition objects
|
|
113
|
+
A list of ToolDefinition objects.
|
|
90
114
|
"""
|
|
91
115
|
return list(self._definitions.values())
|
|
92
116
|
|
|
@@ -103,4 +127,4 @@ class ToolRegistry(metaclass=SingletonMeta):
|
|
|
103
127
|
"""Returns the internal dictionary of definitions."""
|
|
104
128
|
return dict(ToolRegistry._definitions)
|
|
105
129
|
|
|
106
|
-
default_tool_registry = ToolRegistry(
|
|
130
|
+
default_tool_registry = ToolRegistry()
|