mirror of
https://github.com/strands-agents/harness-sdk.git
synced 2026-10-02 02:44:48 +08:00
feat(tools): move ToolProvider out of experimental namespace (#1567)
Co-authored-by: Strands Agent <217235299+strands-agent@users.noreply.github.com>
This commit is contained in:
co-authored by
Strands Agent
parent
27b9bc3acc
commit
4d0ffe84b9
@@ -55,6 +55,7 @@ strands-agents/
|
||||
│ ├── tools/ # Tool system
|
||||
│ │ ├── decorator.py # @tool decorator
|
||||
│ │ ├── tools.py # Tool base classes
|
||||
│ │ ├── tool_provider.py # ToolProvider interface
|
||||
│ │ ├── registry.py # Tool registration
|
||||
│ │ ├── loader.py # Dynamic tool loading
|
||||
│ │ ├── watcher.py # Hot reload
|
||||
@@ -139,8 +140,7 @@ strands-agents/
|
||||
│ │ │ ├── context_providers/
|
||||
│ │ │ ├── core/
|
||||
│ │ │ └── handlers/
|
||||
│ │ └── tools/ # Experimental tools
|
||||
│ │ └── tool_provider.py
|
||||
│ │ └── tools/ # Experimental tools (deprecation shims)
|
||||
│ │
|
||||
│ ├── __init__.py # Public API exports
|
||||
│ ├── interrupt.py # Interrupt handling
|
||||
|
||||
@@ -31,7 +31,7 @@ from ..event_loop.event_loop import INITIAL_DELAY, MAX_ATTEMPTS, MAX_DELAY, even
|
||||
from ..tools._tool_helpers import generate_missing_tool_result_content
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ..experimental.tools import ToolProvider
|
||||
from ..tools import ToolProvider
|
||||
from ..handlers.callback_handler import PrintingCallbackHandler, null_callback_handler
|
||||
from ..hooks import (
|
||||
AfterInvocationEvent,
|
||||
|
||||
@@ -25,11 +25,11 @@ from ....tools._caller import _ToolCaller
|
||||
from ....tools.executors import ConcurrentToolExecutor
|
||||
from ....tools.executors._executor import ToolExecutor
|
||||
from ....tools.registry import ToolRegistry
|
||||
from ....tools.tool_provider import ToolProvider
|
||||
from ....tools.watcher import ToolWatcher
|
||||
from ....types.content import Message, Messages
|
||||
from ....types.tools import AgentTool
|
||||
from ...hooks.events import BidiAgentInitializedEvent, BidiMessageAddedEvent
|
||||
from ...tools import ToolProvider
|
||||
from .._async import _TaskGroup, stop_all
|
||||
from ..models.model import BidiModel
|
||||
from ..types.agent import BidiAgentInput
|
||||
|
||||
@@ -1,5 +1,22 @@
|
||||
"""Experimental tools package."""
|
||||
|
||||
from .tool_provider import ToolProvider
|
||||
import warnings
|
||||
from typing import Any
|
||||
|
||||
__all__ = ["ToolProvider"]
|
||||
_DEPRECATED_NAMES = {"ToolProvider"}
|
||||
|
||||
|
||||
def __getattr__(name: str) -> Any:
|
||||
if name in _DEPRECATED_NAMES:
|
||||
from ...tools import ToolProvider
|
||||
|
||||
warnings.warn(
|
||||
f"{name} has been moved to production. Use {name} from strands.tools instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return ToolProvider
|
||||
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
||||
|
||||
|
||||
__all__: list[str] = []
|
||||
|
||||
@@ -5,6 +5,7 @@ This module provides the core functionality for creating, managing, and executin
|
||||
|
||||
from .decorator import tool
|
||||
from .structured_output import convert_pydantic_to_tool_spec
|
||||
from .tool_provider import ToolProvider
|
||||
from .tools import InvalidToolUseNameException, PythonAgentTool, normalize_schema, normalize_tool_spec
|
||||
|
||||
__all__ = [
|
||||
@@ -14,4 +15,5 @@ __all__ = [
|
||||
"normalize_schema",
|
||||
"normalize_tool_spec",
|
||||
"convert_pydantic_to_tool_spec",
|
||||
"ToolProvider",
|
||||
]
|
||||
|
||||
@@ -40,11 +40,11 @@ from mcp.types import TextContent as MCPTextContent
|
||||
from pydantic import AnyUrl
|
||||
from typing_extensions import Protocol, TypedDict
|
||||
|
||||
from ...experimental.tools import ToolProvider
|
||||
from ...types import PaginatedList
|
||||
from ...types.exceptions import MCPClientInitializationError, ToolProviderException
|
||||
from ...types.media import ImageFormat
|
||||
from ...types.tools import AgentTool, ToolResultContent, ToolResultStatus
|
||||
from ..tool_provider import ToolProvider
|
||||
from .mcp_agent_tool import MCPAgentTool
|
||||
from .mcp_instrumentation import mcp_instrumentation
|
||||
from .mcp_types import MCPToolResult, MCPTransport
|
||||
@@ -106,10 +106,6 @@ class MCPClient(ToolProvider):
|
||||
The connection runs in a background thread to avoid blocking the main application thread
|
||||
while maintaining communication with the MCP service. When structured content is available
|
||||
from MCP tools, it will be returned as the last item in the content array of the ToolResult.
|
||||
|
||||
Warning:
|
||||
This class implements the experimental ToolProvider interface and its methods
|
||||
are subject to change.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -207,7 +203,7 @@ class MCPClient(ToolProvider):
|
||||
raise MCPClientInitializationError("the client initialization failed") from e
|
||||
return self
|
||||
|
||||
# ToolProvider interface methods (experimental, as ToolProvider is experimental)
|
||||
# ToolProvider interface methods
|
||||
async def load_tools(self, **kwargs: Any) -> Sequence[AgentTool]:
|
||||
"""Load and return tools from the MCP server.
|
||||
|
||||
|
||||
@@ -19,9 +19,9 @@ from typing import Any, cast
|
||||
from typing_extensions import TypedDict
|
||||
|
||||
from .._async import run_async
|
||||
from ..experimental.tools import ToolProvider
|
||||
from ..tools.decorator import DecoratedFunctionTool
|
||||
from ..types.tools import AgentTool, ToolSpec
|
||||
from . import ToolProvider
|
||||
from .loader import load_tool_from_string, load_tools_from_module
|
||||
from .tools import _COMPOSITION_KEYWORDS, PythonAgentTool, normalize_schema, normalize_tool_spec
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...types.tools import AgentTool
|
||||
from ..types.tools import AgentTool
|
||||
|
||||
|
||||
class ToolProvider(ABC):
|
||||
@@ -0,0 +1,83 @@
|
||||
"""Tests to verify that experimental ToolProvider alias works with deprecation warning.
|
||||
|
||||
This test module ensures that the experimental ToolProvider alias maintains
|
||||
backwards compatibility and can be used interchangeably with the actual
|
||||
ToolProvider type from strands.tools.
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from strands.tools import ToolProvider
|
||||
|
||||
|
||||
def test_experimental_alias_is_same_type():
|
||||
"""Verify that experimental ToolProvider alias is identical to the actual type."""
|
||||
from strands.experimental.tools import ToolProvider as ExperimentalToolProvider
|
||||
|
||||
assert ExperimentalToolProvider is ToolProvider
|
||||
|
||||
|
||||
def test_deprecation_warning_on_import(captured_warnings):
|
||||
"""Verify that importing ToolProvider from experimental emits deprecation warning."""
|
||||
# Clear the module from cache to trigger fresh import
|
||||
if "strands.experimental.tools" in sys.modules:
|
||||
del sys.modules["strands.experimental.tools"]
|
||||
|
||||
# Clear any existing warnings
|
||||
captured_warnings.clear()
|
||||
|
||||
# Import from experimental - this should trigger the warning
|
||||
from strands.experimental import tools
|
||||
|
||||
_ = tools.ToolProvider
|
||||
|
||||
assert len(captured_warnings) >= 1
|
||||
warning = captured_warnings[0]
|
||||
assert issubclass(warning.category, DeprecationWarning)
|
||||
assert "ToolProvider" in str(warning.message)
|
||||
assert "strands.tools" in str(warning.message)
|
||||
|
||||
|
||||
def test_deprecation_warning_on_direct_import(captured_warnings):
|
||||
"""Verify that direct import from experimental.tools emits deprecation warning."""
|
||||
# Clear the module from cache to trigger fresh import
|
||||
if "strands.experimental.tools" in sys.modules:
|
||||
del sys.modules["strands.experimental.tools"]
|
||||
|
||||
# Clear any existing warnings
|
||||
captured_warnings.clear()
|
||||
|
||||
# Direct import - this should trigger the warning
|
||||
from strands.experimental.tools import ToolProvider as _ # noqa: F401
|
||||
|
||||
assert len(captured_warnings) >= 1
|
||||
warning = captured_warnings[0]
|
||||
assert issubclass(warning.category, DeprecationWarning)
|
||||
assert "ToolProvider" in str(warning.message)
|
||||
assert "strands.tools" in str(warning.message)
|
||||
|
||||
|
||||
def test_attribute_error_on_unknown_attribute():
|
||||
"""Verify that accessing unknown attributes raises AttributeError."""
|
||||
import strands.experimental.tools as tools_module
|
||||
|
||||
with pytest.raises(AttributeError, match="has no attribute"):
|
||||
_ = tools_module.NonExistentClass
|
||||
|
||||
|
||||
def test_no_warning_on_production_import(captured_warnings):
|
||||
"""Verify that importing from strands.tools does not emit deprecation warning."""
|
||||
# Clear any existing warnings
|
||||
captured_warnings.clear()
|
||||
|
||||
# Import from production - should NOT trigger warning
|
||||
from strands.tools import ToolProvider as _ # noqa: F401
|
||||
|
||||
# Filter for ToolProvider-related deprecation warnings
|
||||
tool_provider_warnings = [
|
||||
w for w in captured_warnings if "ToolProvider" in str(w.message) and issubclass(w.category, DeprecationWarning)
|
||||
]
|
||||
|
||||
assert len(tool_provider_warnings) == 0
|
||||
@@ -7,8 +7,7 @@ from unittest.mock import AsyncMock, MagicMock
|
||||
import pytest
|
||||
|
||||
import strands
|
||||
from strands.experimental.tools import ToolProvider
|
||||
from strands.tools import PythonAgentTool
|
||||
from strands.tools import PythonAgentTool, ToolProvider
|
||||
from strands.tools.decorator import DecoratedFunctionTool, tool
|
||||
from strands.tools.mcp import MCPClient
|
||||
from strands.tools.registry import ToolRegistry
|
||||
|
||||
@@ -4,7 +4,7 @@ from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from strands.experimental.tools.tool_provider import ToolProvider
|
||||
from strands.tools import ToolProvider
|
||||
from strands.tools.registry import ToolRegistry
|
||||
from tests.fixtures.mock_agent_tool import MockAgentTool
|
||||
|
||||
|
||||
Reference in New Issue
Block a user