Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 14 additions & 10 deletions src/sap_cloud_sdk/agentgateway/_customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@
_GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials"
_GRANT_TYPE_JWT_BEARER = "urn:ietf:params:oauth:grant-type:jwt-bearer"

# Token response field keys
_TOKEN_FIELD_CLIENT_ID = "client_id"
_TOKEN_FIELD_ACCESS_TOKEN = "access_token"


def _cache_scope_key(credentials: CustomerCredentials) -> str:
"""Build a cache scope key for customer-flow tokens."""
Expand Down Expand Up @@ -147,7 +151,7 @@ def load_customer_credentials_from_env(

# Check required environment variables
required_vars = {
_INTEGRATION_CLIENT_ID_ENV: "client_id",
_INTEGRATION_CLIENT_ID_ENV: _TOKEN_FIELD_CLIENT_ID,
_INTEGRATION_AUTH_URL_ENV: "auth_url",
_INTEGRATION_GATEWAY_URL_ENV: "gateway_url",
}
Expand Down Expand Up @@ -200,7 +204,7 @@ def load_customer_credentials(path: str) -> CustomerCredentials:
# Credential file uses camelCase, we use snake_case
required_fields = {
_CredentialFields.TOKEN_SERVICE_URL: "token_service_url",
_CredentialFields.CLIENT_ID: "client_id",
_CredentialFields.CLIENT_ID: _TOKEN_FIELD_CLIENT_ID,
_CredentialFields.CERTIFICATE: "certificate",
_CredentialFields.PRIVATE_KEY: "private_key",
_CredentialFields.GATEWAY_URL: "gateway_url",
Expand Down Expand Up @@ -324,7 +328,7 @@ def _request_token_mtls(
ssl_context = _create_ssl_context(credentials.certificate, credentials.private_key)

data = {
"client_id": credentials.client_id,
_TOKEN_FIELD_CLIENT_ID: credentials.client_id,
"grant_type": grant_type,
"resource": _AGW_RESOURCE_URN,
}
Expand Down Expand Up @@ -363,7 +367,7 @@ def _request_token_mtls(
)

token_data = response.json()
access_token = token_data.get("access_token")
access_token = token_data.get(_TOKEN_FIELD_ACCESS_TOKEN)

if not access_token:
raise AgentGatewaySDKError(
Expand All @@ -374,7 +378,7 @@ def _request_token_mtls(
return token_data

except httpx.RequestError as e:
raise AgentGatewaySDKError(f"Token request failed: {e}")
raise AgentGatewaySDKError(f"Token request failed: {e}") from e


def _request_token_transparent(
Expand All @@ -401,7 +405,7 @@ def _request_token_transparent(
AgentGatewaySDKError: If token request fails.
"""
data = {
"client_id": credentials.client_id,
_TOKEN_FIELD_CLIENT_ID: credentials.client_id,
"grant_type": grant_type,
"resource": _AGW_RESOURCE_URN,
}
Expand Down Expand Up @@ -437,7 +441,7 @@ def _request_token_transparent(
)

token_data = response.json()
access_token = token_data.get("access_token")
access_token = token_data.get(_TOKEN_FIELD_ACCESS_TOKEN)

if not access_token:
raise AgentGatewaySDKError(
Expand All @@ -448,7 +452,7 @@ def _request_token_transparent(
return token_data

except httpx.RequestError as e:
raise AgentGatewaySDKError(f"Token request failed: {e}")
raise AgentGatewaySDKError(f"Token request failed: {e}") from e


def get_system_token_mtls(
Expand Down Expand Up @@ -499,7 +503,7 @@ def get_system_token_mtls(
extra_data={"response_type": "token"},
)

access_token = token_data["access_token"]
access_token = token_data[_TOKEN_FIELD_ACCESS_TOKEN]

if token_cache:
token_cache.set_system_token(
Expand Down Expand Up @@ -571,7 +575,7 @@ def exchange_user_token(
},
)

access_token = token_data["access_token"]
access_token = token_data[_TOKEN_FIELD_ACCESS_TOKEN]

if token_cache:
token_cache.set_user_token(
Expand Down
12 changes: 7 additions & 5 deletions src/sap_cloud_sdk/agentgateway/agw_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,12 @@
)
from sap_cloud_sdk.agentgateway._token_cache import _GatewayUrlCache, _TokenCache
from sap_cloud_sdk.agentgateway.exceptions import AgentGatewaySDKError
from sap_cloud_sdk.core._telemetry_compat import Module, Operation, record_metrics
from sap_cloud_sdk.core.telemetry import Module, Operation, record_metrics

logger = logging.getLogger(__name__)

_LOG_TRANSPARENT_MODE = "Transparent mode credentials detected"


class AgentGatewayClient:
"""Client for discovering and invoking MCP tools via SAP Agent Gateway.
Expand Down Expand Up @@ -197,7 +199,7 @@ async def get_system_auth(self) -> AuthResult:

# Check for transparent mode
if detect_transparent_credentials():
logger.info("Transparent mode credentials detected")
logger.info(_LOG_TRANSPARENT_MODE)
credentials = load_customer_credentials_from_env()
loop = asyncio.get_running_loop()
token = await loop.run_in_executor(
Expand Down Expand Up @@ -283,7 +285,7 @@ async def get_user_auth(

# Check for transparent mode
if detect_transparent_credentials():
logger.info("Transparent mode credentials detected")
logger.info(_LOG_TRANSPARENT_MODE)
credentials = load_customer_credentials_from_env()
loop = asyncio.get_running_loop()
token = await loop.run_in_executor(
Expand Down Expand Up @@ -406,7 +408,7 @@ async def list_mcp_tools(

# Check for transparent mode
if detect_transparent_credentials():
logger.info("Transparent mode credentials detected")
logger.info(_LOG_TRANSPARENT_MODE)
credentials = load_customer_credentials_from_env()
return await get_mcp_tools_customer(
credentials, auth.access_token, self._config.timeout
Expand Down Expand Up @@ -560,7 +562,7 @@ async def call_mcp_tool(

# Check for transparent mode
if detect_transparent_credentials():
logger.debug("Transparent mode credentials detected")
logger.debug(_LOG_TRANSPARENT_MODE)

return await call_mcp_tool_customer(
tool, auth.access_token, self._config.timeout, **kwargs
Expand Down
27 changes: 0 additions & 27 deletions src/sap_cloud_sdk/core/_telemetry_compat.py

This file was deleted.

2 changes: 1 addition & 1 deletion src/sap_cloud_sdk/destination/certificate_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from typing import List, Optional, TypeVar, Callable

from sap_cloud_sdk.core._telemetry_compat import Module, Operation, record_metrics
from sap_cloud_sdk.core.telemetry import Module, Operation, record_metrics
from sap_cloud_sdk.destination._http import DestinationHttp, API_V1
from sap_cloud_sdk.destination._models import (
AccessStrategy,
Expand Down
4 changes: 1 addition & 3 deletions src/sap_cloud_sdk/destination/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
import warnings
from typing import Any, Dict, List, Optional, Callable, TypeVar

# Conditional telemetry import - works even when telemetry packages are not installed
from sap_cloud_sdk.core._telemetry_compat import Module, Operation, record_metrics

from sap_cloud_sdk.core.telemetry import Module, Operation, record_metrics
from sap_cloud_sdk.core.secret_resolver import read_from_mount_and_fallback_to_env_var
from sap_cloud_sdk.destination._http import DestinationHttp, API_V1, API_V2
from sap_cloud_sdk.destination._models import (
Expand Down
2 changes: 1 addition & 1 deletion src/sap_cloud_sdk/destination/fragment_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from typing import Callable, List, Optional, TypeVar

from sap_cloud_sdk.core._telemetry_compat import Module, Operation, record_metrics
from sap_cloud_sdk.core.telemetry import Module, Operation, record_metrics
from sap_cloud_sdk.destination._http import DestinationHttp, API_V1
from sap_cloud_sdk.destination._models import (
AccessStrategy,
Expand Down
4 changes: 2 additions & 2 deletions tests/agentgateway/unit/test_lob.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
from sap_cloud_sdk.agentgateway._models import Agent, AgentCard, MCPTool
from sap_cloud_sdk.agentgateway._token_cache import _GatewayUrlCache, _TokenCache
from sap_cloud_sdk.agentgateway.config import ClientConfig
from sap_cloud_sdk.destination import ConsumptionOptions, ConsumptionLevel
from sap_cloud_sdk.agentgateway.exceptions import AgentGatewaySDKError, MCPServerNotFoundError
from sap_cloud_sdk.destination import ConsumptionLevel, ConsumptionOptions
from sap_cloud_sdk.destination import ConsumptionLevel

# Aliases for use in existing test assertions
_LABEL_KEY = LABEL_KEY
Expand Down Expand Up @@ -1065,4 +1066,3 @@ def test_raises_when_landscape_env_not_set(self):
with patch("sap_cloud_sdk.agentgateway._lob._ias_dest_name", side_effect=EnvironmentError("APPFND_CONHOS_LANDSCAPE not set")):
with pytest.raises(EnvironmentError, match="APPFND_CONHOS_LANDSCAPE"):
get_ias_client_id_lob()