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
9 changes: 3 additions & 6 deletions agentkit/client/base_agentkit_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
from typing import Any, Dict, Union, Optional

from agentkit.client.base_service_client import BaseServiceClient, ApiConfig
from agentkit.utils.ve_sign import get_volc_agentkit_host_info
from agentkit.toolkit.config.global_config import get_global_config
from agentkit.utils.ve_sign import get_volc_agentkit_host_info, get_volc_agentkit_scheme


class BaseAgentkitClient(BaseServiceClient):
Expand Down Expand Up @@ -78,13 +77,11 @@ def _get_service_config(self) -> Dict[str, str]:
Dictionary with host, api_version, and service
"""
host, api_version, service = get_volc_agentkit_host_info()
gc = get_global_config()
scheme = gc.agentkit_schema or "https"
return {
"host": gc.agentkit_host or host,
"host": host,
"api_version": api_version,
"service": service,
"scheme": scheme,
"scheme": get_volc_agentkit_scheme(),
}

def _get(self, api_action: str, params: Dict[str, Any] = None) -> str:
Expand Down
8 changes: 3 additions & 5 deletions agentkit/client/base_iam_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from typing import Dict, Union

from agentkit.client.base_service_client import BaseServiceClient, ApiConfig
from agentkit.toolkit.config.global_config import get_global_config
from agentkit.utils.ve_sign import get_volc_iam_host_scheme


class BaseIAMClient(BaseServiceClient):
Expand Down Expand Up @@ -79,11 +79,9 @@ def _get_service_config(self) -> Dict[str, str]:
Returns:
Dictionary with host, api_version, and service
"""
gc = get_global_config()
scheme = gc.iam_schema or "https"
host = gc.iam_host or self.IAM_HOST
host, scheme = get_volc_iam_host_scheme()
return {
"host": host,
"host": host or self.IAM_HOST,
"api_version": self.IAM_API_VERSION,
"service": self.IAM_SERVICE_CODE,
"scheme": scheme,
Expand Down
48 changes: 47 additions & 1 deletion agentkit/toolkit/cli/cli_launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,66 @@
def launch_command(
config_file: Path = typer.Option("agentkit.yaml", help="Configuration file"),
platform: str = typer.Option("auto", help="Build platform"),
preflight_mode: str = typer.Option(
"",
"--preflight-mode",
help="Preflight behavior: prompt|fail|warn|skip",
),
):
"""Build and deploy in one command."""
from agentkit.toolkit.executors import LifecycleExecutor
from agentkit.toolkit.cli.console_reporter import ConsoleReporter
from agentkit.toolkit.context import ExecutionContext
from agentkit.toolkit.models import PreflightMode
from agentkit.toolkit.config.global_config import get_global_config

console.print("[green]Launching agent...[/green]")

# Set execution context - CLI uses ConsoleReporter (with colored output and progress)
reporter = ConsoleReporter()
ExecutionContext.set_reporter(reporter)

resolved_mode = PreflightMode.PROMPT
mode_map = {
"prompt": PreflightMode.PROMPT,
"fail": PreflightMode.FAIL,
"warn": PreflightMode.WARN,
"skip": PreflightMode.SKIP,
}

cli_mode = preflight_mode.strip().lower()
if cli_mode:
if cli_mode not in mode_map:
console.print(
"[red]Invalid --preflight-mode. Allowed: prompt|fail|warn|skip[/red]"
)
raise typer.Exit(2)
resolved_mode = mode_map[cli_mode]
else:
try:
gm = (
(
getattr(
getattr(get_global_config(), "defaults", None),
"preflight_mode",
None,
)
or ""
)
.strip()
.lower()
)
if gm in mode_map:
resolved_mode = mode_map[gm]
except Exception:
pass

executor = LifecycleExecutor(reporter=reporter)
result = executor.launch(config_file=str(config_file), platform=platform)
result = executor.launch(
config_file=str(config_file),
platform=platform,
preflight_mode=resolved_mode,
)

# Format output
if result.success:
Expand Down
41 changes: 12 additions & 29 deletions agentkit/toolkit/config/global_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@
from typing import Optional
import logging

from agentkit.utils.global_config_io import (
read_global_config_dict,
write_global_config_dict,
)

from .utils import is_valid_config

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -228,20 +233,18 @@ def load(self) -> GlobalConfig:
Returns:
GlobalConfig instance
"""
if not self.config_path.exists():
logger.debug(f"Global config file does not exist: {self.config_path}")
data = read_global_config_dict(self.config_path)
if not data:
logger.debug(
f"Global config file does not exist or empty: {self.config_path}"
)
return GlobalConfig()

try:
import yaml

with open(self.config_path, "r", encoding="utf-8") as f:
data = yaml.safe_load(f) or {}
logger.debug(f"Loaded global config from: {self.config_path}")
return GlobalConfig.from_dict(data)
except Exception as e:
logger.debug(
f"Failed to load global config, using empty config: {e}", exc_info=True
f"Failed to parse global config, using empty config: {e}", exc_info=True
)
return GlobalConfig()

Expand All @@ -251,27 +254,7 @@ def save(self, config: GlobalConfig):
Args:
config: Configuration object to persist
"""
# Ensure parent directory exists
self.config_path.parent.mkdir(parents=True, exist_ok=True)

# Write YAML config
with open(self.config_path, "w", encoding="utf-8") as f:
import yaml

yaml.dump(
config.to_dict(),
f,
default_flow_style=False,
allow_unicode=True,
sort_keys=False,
)

# Restrict file permission to owner read/write only
try:
self.config_path.chmod(0o600)
except Exception as e:
logger.warning(f"Failed to set config file permission: {e}")

write_global_config_dict(config.to_dict(), self.config_path)
logger.info(f"Global config saved: {self.config_path}")

def get_config(self, force_reload: bool = False) -> GlobalConfig:
Expand Down
17 changes: 0 additions & 17 deletions agentkit/toolkit/executors/lifecycle_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,23 +144,6 @@ def launch(

# Preflight check: verify required cloud services for both build and deploy
# We do this once at the start for better UX (single prompt for all missing services)
# Override preflight_mode from global config defaults if configured
try:
from agentkit.toolkit.config.global_config import get_global_config

gc = get_global_config()
gm = getattr(getattr(gc, "defaults", None), "preflight_mode", None)
if gm:
gm_map = {
"prompt": PreflightMode.PROMPT,
"fail": PreflightMode.FAIL,
"warn": PreflightMode.WARN,
"skip": PreflightMode.SKIP,
}
preflight_mode = gm_map.get(gm.lower(), preflight_mode)
except Exception:
pass

if preflight_mode != PreflightMode.SKIP:
# Load config first to get launch_type
config = self._load_config(config_dict, config_file)
Expand Down
28 changes: 0 additions & 28 deletions agentkit/toolkit/runners/ve_agentkit.py
Original file line number Diff line number Diff line change
Expand Up @@ -584,34 +584,6 @@ def _build_authorizer_config_for_create(
)
)

def _build_authorizer_config_for_update(
self, config: VeAgentkitRunnerConfig
) -> runtime_types.AuthorizerForUpdateRuntime:
"""Build authorizer configuration for updating an existing Runtime.

Args:
config: Runner configuration.

Returns:
AuthorizerForUpdateRuntime: Authorizer configuration for update request.
"""
if config.runtime_auth_type == AUTH_TYPE_CUSTOM_JWT:
return runtime_types.AuthorizerForUpdateRuntime(
custom_jwt_authorizer=runtime_types.AuthorizerCustomJwtAuthorizerForUpdateRuntime(
discovery_url=config.runtime_jwt_discovery_url,
allowed_clients=config.runtime_jwt_allowed_clients
if config.runtime_jwt_allowed_clients
else None,
)
)
else:
return runtime_types.AuthorizerForUpdateRuntime(
key_auth=runtime_types.AuthorizerKeyAuthForUpdateRuntime(
api_key_name=config.runtime_apikey_name,
api_key_location=API_KEY_LOCATION,
)
)

def _create_new_runtime(self, config: VeAgentkitRunnerConfig) -> DeployResult:
"""Create a new Runtime instance.

Expand Down
118 changes: 118 additions & 0 deletions agentkit/utils/global_config_io.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from __future__ import annotations

from pathlib import Path
from typing import Any, Optional, Tuple


_cache: Tuple[Optional[float], dict] = (None, {})


def get_default_global_config_path() -> Path:
return Path.home() / ".agentkit" / "config.yaml"


def read_global_config_dict(
config_path: Optional[Path] = None,
*,
force_reload: bool = False,
) -> dict:
global _cache

path = config_path or get_default_global_config_path()

try:
mtime = path.stat().st_mtime
except FileNotFoundError:
if force_reload:
_cache = (None, {})
return {}
except Exception:
return {}

cached_mtime, cached_data = _cache
if not force_reload and cached_mtime == mtime:
return cached_data

try:
import yaml

with open(path, "r", encoding="utf-8") as f:
data = yaml.safe_load(f) or {}
parsed = data if isinstance(data, dict) else {}
_cache = (mtime, parsed)
return parsed
except Exception:
return {}


def write_global_config_dict(
data: dict,
config_path: Optional[Path] = None,
) -> None:
global _cache

path = config_path or get_default_global_config_path()
path.parent.mkdir(parents=True, exist_ok=True)

import yaml

with open(path, "w", encoding="utf-8") as f:
yaml.dump(
data,
f,
default_flow_style=False,
allow_unicode=True,
sort_keys=False,
)

try:
path.chmod(0o600)
except Exception:
pass

try:
mtime = path.stat().st_mtime
_cache = (mtime, data)
except Exception:
pass


def get_path_value(data: Any, *keys: str) -> Any:
cur = data
for key in keys:
if not isinstance(cur, dict):
return None
cur = cur.get(key)
return cur


def get_global_config_str(
*keys: str,
fallback_keys: Optional[Tuple[str, ...]] = None,
config_path: Optional[Path] = None,
) -> str:
data = read_global_config_dict(config_path)
v = get_path_value(data, *keys)
if isinstance(v, str) and v:
return v
if fallback_keys:
v2 = get_path_value(data, *fallback_keys)
if isinstance(v2, str) and v2:
return v2
return ""


def get_global_config_bool(
*keys: str,
fallback_keys: Optional[Tuple[str, ...]] = None,
config_path: Optional[Path] = None,
):
data = read_global_config_dict(config_path)
v = get_path_value(data, *keys)
if isinstance(v, bool):
return v
if fallback_keys:
v2 = get_path_value(data, *fallback_keys)
if isinstance(v2, bool):
return v2
return None
Loading