mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
Fourth and final transport — completes the transport layer with all four api_modes covered. Wraps agent/bedrock_adapter.py behind the ProviderTransport ABC, handles both raw boto3 dicts and already-normalized SimpleNamespace. Wires all transport methods to production paths in run_agent.py: - build_kwargs: _build_api_kwargs bedrock branch - validate_response: response validation, new bedrock_converse branch - finish_reason: new bedrock_converse branch in finish_reason extraction Based on PR #13467 by @kshitijk4poor, with one adjustment: the main normalize loop does NOT add a bedrock_converse branch to invoke normalize_response on the already-normalized response. Bedrock's normalize_converse_response runs at the dispatch site (run_agent.py:5189), so the response already has the OpenAI-compatible .choices[0].message shape by the time the main loop sees it. Falling through to the chat_completions else branch is correct and sidesteps a redundant NormalizedResponse rebuild. Transport coverage — complete: | api_mode | Transport | build_kwargs | normalize | validate | |--------------------|--------------------------|:------------:|:---------:|:--------:| | anthropic_messages | AnthropicTransport | ✅ | ✅ | ✅ | | codex_responses | ResponsesApiTransport | ✅ | ✅ | ✅ | | chat_completions | ChatCompletionsTransport | ✅ | ✅ | ✅ | | bedrock_converse | BedrockTransport | ✅ | ✅ | ✅ | 17 new BedrockTransport tests pass. 117 transport tests total pass. 160 bedrock/converse tests across tests/agent/ pass. Full tests/run_agent/ targeted suite passes (885/885 + 15 skipped; the 1 remaining failure is the pre-existing test_concurrent_interrupt flake on origin/main).
51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
"""Transport layer types and registry for provider response normalization.
|
|
|
|
Usage:
|
|
from agent.transports import get_transport
|
|
transport = get_transport("anthropic_messages")
|
|
result = transport.normalize_response(raw_response)
|
|
"""
|
|
|
|
from agent.transports.types import NormalizedResponse, ToolCall, Usage, build_tool_call, map_finish_reason # noqa: F401
|
|
|
|
_REGISTRY: dict = {}
|
|
|
|
|
|
def register_transport(api_mode: str, transport_cls: type) -> None:
|
|
"""Register a transport class for an api_mode string."""
|
|
_REGISTRY[api_mode] = transport_cls
|
|
|
|
|
|
def get_transport(api_mode: str):
|
|
"""Get a transport instance for the given api_mode.
|
|
|
|
Returns None if no transport is registered for this api_mode.
|
|
This allows gradual migration — call sites can check for None
|
|
and fall back to the legacy code path.
|
|
"""
|
|
if not _REGISTRY:
|
|
_discover_transports()
|
|
cls = _REGISTRY.get(api_mode)
|
|
if cls is None:
|
|
return None
|
|
return cls()
|
|
|
|
|
|
def _discover_transports() -> None:
|
|
"""Import all transport modules to trigger auto-registration."""
|
|
try:
|
|
import agent.transports.anthropic # noqa: F401
|
|
except ImportError:
|
|
pass
|
|
try:
|
|
import agent.transports.codex # noqa: F401
|
|
except ImportError:
|
|
pass
|
|
try:
|
|
import agent.transports.chat_completions # noqa: F401
|
|
except ImportError:
|
|
pass
|
|
try:
|
|
import agent.transports.bedrock # noqa: F401
|
|
except ImportError:
|
|
pass
|