mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-17 09:41:58 +00:00
fix(bedrock): check boto3 version >= 1.34.59 before using converse_stream
converse() and converse_stream() were added in boto3 1.34.59. When Hermes is installed editable into system Python (e.g. Ubuntu 24.04 ships 1.34.46), the system boto3 takes precedence and calls to converse_stream fail with AttributeError. Add an early version check in _require_boto3() that raises a clear RuntimeError with upgrade instructions.
This commit is contained in:
parent
f79b109f4f
commit
2cddc9c895
2 changed files with 68 additions and 2 deletions
|
|
@ -58,17 +58,34 @@ _bedrock_runtime_client_cache: Dict[str, Any] = {}
|
|||
_bedrock_control_client_cache: Dict[str, Any] = {}
|
||||
|
||||
|
||||
_MIN_BOTO3_VERSION = (1, 34, 59)
|
||||
|
||||
|
||||
def _require_boto3():
|
||||
"""Import boto3, raising a clear error if not installed."""
|
||||
"""Import boto3, raising a clear error if not installed or too old."""
|
||||
try:
|
||||
import boto3
|
||||
return boto3
|
||||
except ImportError:
|
||||
raise ImportError(
|
||||
"The 'boto3' package is required for the AWS Bedrock provider. "
|
||||
"Install it with: pip install boto3\n"
|
||||
"Or install Hermes with Bedrock support: pip install -e '.[bedrock]'"
|
||||
)
|
||||
# converse() / converse_stream() were added in boto3 1.34.59.
|
||||
# When Hermes is installed editable into system Python, the system boto3
|
||||
# (e.g. Ubuntu 24.04 ships 1.34.46) may take precedence over the venv
|
||||
# version pinned in pyproject.toml.
|
||||
try:
|
||||
version = tuple(int(x) for x in boto3.__version__.split(".")[:3])
|
||||
except (AttributeError, ValueError):
|
||||
return boto3 # can't parse — don't block on version check
|
||||
if version < _MIN_BOTO3_VERSION:
|
||||
raise RuntimeError(
|
||||
f"boto3 {boto3.__version__} does not support converse_stream "
|
||||
f"(minimum 1.34.59 required). Upgrade with: "
|
||||
f"pip install --upgrade boto3"
|
||||
)
|
||||
return boto3
|
||||
|
||||
|
||||
def _get_bedrock_runtime_client(region: str):
|
||||
|
|
|
|||
|
|
@ -1663,3 +1663,52 @@ class TestCallConverseStreamIamFallback:
|
|||
assert result.choices[0].message.content == "hi"
|
||||
# Not a stale connection — client stays cached.
|
||||
assert _bedrock_runtime_client_cache.get("us-east-1") is client
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# boto3 version check
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
class TestRequireBoto3VersionCheck:
|
||||
"""Test that _require_boto3() rejects boto3 versions older than 1.34.59."""
|
||||
|
||||
def test_raises_runtime_error_when_boto3_too_old(self):
|
||||
"""boto3 < 1.34.59 should raise RuntimeError with upgrade instructions."""
|
||||
from agent.bedrock_adapter import _require_boto3
|
||||
|
||||
fake_boto3 = MagicMock()
|
||||
fake_boto3.__version__ = "1.34.46"
|
||||
with patch.dict("sys.modules", {"boto3": fake_boto3}):
|
||||
with pytest.raises(RuntimeError, match="does not support converse_stream"):
|
||||
_require_boto3()
|
||||
|
||||
def test_accepts_boto3_at_minimum_version(self):
|
||||
"""boto3 == 1.34.59 should be accepted."""
|
||||
from agent.bedrock_adapter import _require_boto3
|
||||
|
||||
fake_boto3 = MagicMock()
|
||||
fake_boto3.__version__ = "1.34.59"
|
||||
with patch.dict("sys.modules", {"boto3": fake_boto3}):
|
||||
result = _require_boto3()
|
||||
assert result is fake_boto3
|
||||
|
||||
def test_accepts_newer_boto3(self):
|
||||
"""boto3 > 1.34.59 should be accepted."""
|
||||
from agent.bedrock_adapter import _require_boto3
|
||||
|
||||
fake_boto3 = MagicMock()
|
||||
fake_boto3.__version__ = "1.42.89"
|
||||
with patch.dict("sys.modules", {"boto3": fake_boto3}):
|
||||
result = _require_boto3()
|
||||
assert result is fake_boto3
|
||||
|
||||
def test_accepts_boto3_with_unparseable_version(self):
|
||||
"""If version string can't be parsed, don't block on version check."""
|
||||
from agent.bedrock_adapter import _require_boto3
|
||||
|
||||
fake_boto3 = MagicMock()
|
||||
fake_boto3.__version__ = "dev"
|
||||
with patch.dict("sys.modules", {"boto3": fake_boto3}):
|
||||
result = _require_boto3()
|
||||
assert result is fake_boto3
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue