Skip to content

Commit 46b5a30

Browse files
authored
refactor: refactoring service configuration and credential management (#40)
2 parents 0b43882 + 5307a48 commit 46b5a30

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1701
-660
lines changed

.gitleaks.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,7 @@ description = "Empty environment variables with KEY pattern"
7373
regex = '''os\.environ\[".*?KEY"\]\s*=\s*".+"'''
7474

7575
[allowlist]
76-
paths = ["requirements.txt"]
76+
paths = [
77+
"requirements.txt",
78+
"tests/platform/test_configuration_creds.py"
79+
]

agentkit/apps/agent_server_app/agent_server_app.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -103,9 +103,7 @@ def __init__(
103103
@asynccontextmanager
104104
async def lifespan(app: FastAPI):
105105
# trigger A2A server app startup
106-
logger.info(
107-
"Triggering A2A server app startup within API server..."
108-
)
106+
logger.info("Triggering A2A server app startup within API server...")
109107
for handler in _a2a_server_app.router.on_startup:
110108
await handler()
111109
yield
@@ -124,18 +122,14 @@ async def _invoke_compat(request: Request):
124122
# Extract headers (fallback keys supported)
125123
headers = request.headers
126124
user_id = (
127-
headers.get("user_id")
128-
or headers.get("x-user-id")
129-
or "agentkit_user"
125+
headers.get("user_id") or headers.get("x-user-id") or "agentkit_user"
130126
)
131127
session_id = headers.get("session_id") or ""
132128

133129
# Determine app_name from loader
134130
app_names = self.server.agent_loader.list_agents()
135131
if not app_names:
136-
raise HTTPException(
137-
status_code=404, detail="No agents configured"
138-
)
132+
raise HTTPException(status_code=404, detail="No agents configured")
139133
app_name = app_names[0]
140134

141135
# Parse payload and convert to ADK Content
@@ -184,9 +178,7 @@ async def event_generator():
184178
user_id=user_id,
185179
session_id=session_id,
186180
new_message=content,
187-
run_config=RunConfig(
188-
streaming_mode=StreamingMode.SSE
189-
),
181+
run_config=RunConfig(streaming_mode=StreamingMode.SSE),
190182
)
191183
) as agen:
192184
async for event in agen:

agentkit/client/base_agentkit_client.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from typing import Any, Dict, Union, Optional
2121

2222
from agentkit.client.base_service_client import BaseServiceClient, ApiConfig
23-
from agentkit.utils.ve_sign import get_volc_agentkit_host_info, get_volc_agentkit_scheme
2423

2524

2625
class BaseAgentkitClient(BaseServiceClient):
@@ -60,30 +59,15 @@ def __init__(
6059
service_name: Service name for logging (e.g., 'knowledge', 'memory')
6160
"""
6261
super().__init__(
62+
service="agentkit",
6363
access_key=access_key,
6464
secret_key=secret_key,
6565
region=region,
6666
session_token=session_token,
6767
service_name=service_name,
68-
credential_env_prefix="AGENTKIT",
6968
header=header,
7069
)
7170

72-
def _get_service_config(self) -> Dict[str, str]:
73-
"""
74-
Get AgentKit service configuration.
75-
76-
Returns:
77-
Dictionary with host, api_version, and service
78-
"""
79-
host, api_version, service = get_volc_agentkit_host_info()
80-
return {
81-
"host": host,
82-
"api_version": api_version,
83-
"service": service,
84-
"scheme": get_volc_agentkit_scheme(),
85-
}
86-
8771
def _get(self, api_action: str, params: Dict[str, Any] = None) -> str:
8872
"""Legacy method for GET requests."""
8973
try:

agentkit/client/base_iam_client.py

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from typing import Dict, Union
2121

2222
from agentkit.client.base_service_client import BaseServiceClient, ApiConfig
23-
from agentkit.utils.ve_sign import get_volc_iam_host_scheme
2423

2524

2625
class BaseIAMClient(BaseServiceClient):
@@ -64,25 +63,10 @@ def __init__(
6463
service_name: Service name for logging
6564
"""
6665
super().__init__(
66+
service="iam",
6767
access_key=access_key,
6868
secret_key=secret_key,
6969
region=region,
7070
session_token=session_token,
7171
service_name=service_name,
72-
credential_env_prefix="IAM",
7372
)
74-
75-
def _get_service_config(self) -> Dict[str, str]:
76-
"""
77-
Get IAM service configuration.
78-
79-
Returns:
80-
Dictionary with host, api_version, and service
81-
"""
82-
host, scheme = get_volc_iam_host_scheme()
83-
return {
84-
"host": host or self.IAM_HOST,
85-
"api_version": self.IAM_API_VERSION,
86-
"service": self.IAM_SERVICE_CODE,
87-
"scheme": scheme,
88-
}

agentkit/client/base_service_client.py

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626
from volcengine.Credentials import Credentials
2727
from volcengine.ServiceInfo import ServiceInfo
2828

29-
from agentkit.utils.ve_sign import (
30-
get_volc_ak_sk_region,
31-
ensure_x_custom_source_header,
29+
from agentkit.platform import (
30+
VolcConfiguration,
31+
resolve_credentials,
32+
resolve_endpoint,
3233
)
34+
from agentkit.utils.ve_sign import ensure_x_custom_source_header
3335

3436
T = TypeVar("T")
3537

@@ -62,52 +64,61 @@ class BaseServiceClient(Service):
6264
6365
Subclasses should:
6466
1. Override API_ACTIONS with their API action configurations
65-
2. Implement _get_service_config() to provide service-specific configuration
6667
"""
6768

6869
# Subclasses should override this with their API action configurations
6970
API_ACTIONS: Dict[str, Union[str, ApiConfig]] = {}
7071

7172
def __init__(
7273
self,
74+
service: str,
7375
access_key: str = "",
7476
secret_key: str = "",
7577
region: str = "",
7678
session_token: str = "",
7779
service_name: str = "",
78-
credential_env_prefix: str = "",
80+
platform_config: Optional[VolcConfiguration] = None,
7981
header: Optional[Dict[str, Any]] = None,
8082
) -> None:
8183
"""
8284
Initialize the service client.
8385
8486
Args:
87+
service: Logical service name for signing and endpoint resolution
8588
access_key: Volcengine access key
8689
secret_key: Volcengine secret key
87-
region: Volcengine region
90+
region: Volcengine region override for endpoint
8891
session_token: Optional session token
8992
service_name: Service name for logging
90-
credential_env_prefix: Environment variable prefix for credentials (e.g., 'AGENTKIT', 'IAM')
93+
platform_config: Optional platform-level configuration overrides
9194
"""
92-
# Validate and get credentials
93-
if not any([access_key, secret_key, region]):
94-
access_key, secret_key, region = get_volc_ak_sk_region(
95-
credential_env_prefix
96-
)
97-
else:
98-
if not all([access_key, secret_key, region]):
99-
raise ValueError(
100-
f"Error creating {service_name} instance: "
101-
"missing access key, secret key or region"
102-
)
95+
if platform_config is None:
96+
platform_config = VolcConfiguration()
97+
98+
creds = resolve_credentials(
99+
service=service,
100+
explicit_access_key=access_key or None,
101+
explicit_secret_key=secret_key or None,
102+
platform_config=platform_config,
103+
)
104+
105+
ep = resolve_endpoint(
106+
service=service,
107+
region=region or None,
108+
platform_config=platform_config,
109+
)
103110

104-
# Store credentials and service info
105-
self.access_key = access_key
106-
self.secret_key = secret_key
107-
self.region = region
111+
self.access_key = creds.access_key
112+
self.secret_key = creds.secret_key
113+
self.region = ep.region
108114
self.session_token = session_token
109115
self.service_name = service_name
110116

117+
self.host = ep.host
118+
self.api_version = ep.api_version
119+
self.service = ep.service
120+
self.scheme = ep.scheme
121+
111122
if header is None:
112123
effective_header: Dict[str, Any] = {"Accept": "application/json"}
113124
else:
@@ -116,14 +127,6 @@ def __init__(
116127
effective_header = {"Accept": "application/json", **effective_header}
117128

118129
effective_header = ensure_x_custom_source_header(effective_header)
119-
120-
# Get service-specific configuration from subclass
121-
config = self._get_service_config()
122-
self.host = config["host"]
123-
self.api_version = config["api_version"]
124-
self.service = config["service"]
125-
self.scheme = config.get("scheme", "https")
126-
127130
# Create ServiceInfo
128131
self.service_info = ServiceInfo(
129132
host=self.host,
@@ -145,20 +148,9 @@ def __init__(
145148

146149
# Initialize parent Service class
147150
Service.__init__(self, service_info=self.service_info, api_info=self.api_info)
148-
149-
def _get_service_config(self) -> Dict[str, str]:
150-
"""
151-
Get service-specific configuration.
152-
153-
Subclasses must override this method to provide:
154-
- host: API endpoint host
155-
- api_version: API version string
156-
- service: Service name for signing
157-
158-
Returns:
159-
Dictionary with 'host', 'api_version', and 'service' keys
160-
"""
161-
raise NotImplementedError("Subclasses must implement _get_service_config()")
151+
# need setting ak/sk after initializing Service to avoid volcengine SDK bugs
152+
self.set_ak(self.access_key)
153+
self.set_sk(self.secret_key)
162154

163155
def _build_api_info(self) -> Dict[str, ApiInfo]:
164156
"""

agentkit/platform/__init__.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
from __future__ import annotations
16+
17+
from typing import Optional
18+
19+
from agentkit.platform.configuration import VolcConfiguration, Endpoint, Credentials
20+
from agentkit.platform.constants import DEFAULT_REGION_RULES
21+
22+
__all__ = [
23+
"VolcConfiguration",
24+
"Endpoint",
25+
"Credentials",
26+
"resolve_endpoint",
27+
"resolve_credentials",
28+
"DEFAULT_REGION_RULES",
29+
]
30+
31+
# Backward compatibility wrappers
32+
33+
34+
def resolve_endpoint(
35+
service: str,
36+
*,
37+
region: Optional[str] = None,
38+
platform_config: Optional[VolcConfiguration] = None,
39+
) -> Endpoint:
40+
"""
41+
Resolves the endpoint for a service.
42+
43+
Args:
44+
service: Service identifier (e.g. 'agentkit', 'cr')
45+
region: Explicit region override
46+
platform_config: Optional configuration object. If provided, 'region' arg overrides config.
47+
"""
48+
# If region is provided explicitly, it should override the config's region.
49+
# We can achieve this by creating a new ephemeral config or just letting VolcConfiguration handle it?
50+
# Since VolcConfiguration is immutable-ish, we can just instantiate one if needed.
51+
52+
if platform_config:
53+
# If explicit region is passed, it overrides the config's region for this call
54+
if region and region != platform_config.region:
55+
# Create a temporary lightweight clone with new region, keeping creds
56+
# Or more simply, VolcConfiguration handles service-specific region overrides internally
57+
# but here 'region' is a global override for this call.
58+
# Let's create a new config merging both.
59+
cfg = VolcConfiguration(
60+
region=region,
61+
access_key=platform_config._ak,
62+
secret_key=platform_config._sk,
63+
)
64+
else:
65+
cfg = platform_config
66+
else:
67+
cfg = VolcConfiguration(region=region)
68+
69+
return cfg.get_service_endpoint(service)
70+
71+
72+
def resolve_credentials(
73+
service: str,
74+
*,
75+
explicit_access_key: Optional[str] = None,
76+
explicit_secret_key: Optional[str] = None,
77+
platform_config: Optional[VolcConfiguration] = None,
78+
) -> Credentials:
79+
"""
80+
Resolves credentials for a service.
81+
"""
82+
# 1. Explicit args take absolute precedence
83+
if explicit_access_key and explicit_secret_key:
84+
return Credentials(
85+
access_key=explicit_access_key, secret_key=explicit_secret_key
86+
)
87+
88+
cfg = platform_config or VolcConfiguration()
89+
return cfg.get_service_credentials(service)

0 commit comments

Comments
 (0)