diff --git a/openviking/server/config.py b/openviking/server/config.py index 2fdbcbdf..b11d1c90 100644 --- a/openviking/server/config.py +++ b/openviking/server/config.py @@ -8,11 +8,15 @@ from openviking_cli.utils import get_logger from openviking_cli.utils.config.config_loader import ( - DEFAULT_OV_CONF, - OPENVIKING_CONFIG_ENV, load_json_config, resolve_config_path, ) +from openviking_cli.utils.config.consts import ( + DEFAULT_CONFIG_DIR, + DEFAULT_OV_CONF, + OPENVIKING_CONFIG_ENV, + SYSTEM_CONFIG_DIR, +) logger = get_logger(__name__) @@ -52,12 +56,11 @@ def load_server_config(config_path: Optional[str] = None) -> ServerConfig: """ path = resolve_config_path(config_path, OPENVIKING_CONFIG_ENV, DEFAULT_OV_CONF) if path is None: - from openviking_cli.utils.config.config_loader import DEFAULT_CONFIG_DIR - - default_path = DEFAULT_CONFIG_DIR / DEFAULT_OV_CONF + default_path_user = DEFAULT_CONFIG_DIR / DEFAULT_OV_CONF + default_path_system = SYSTEM_CONFIG_DIR / DEFAULT_OV_CONF raise FileNotFoundError( f"OpenViking configuration file not found.\n" - f"Please create {default_path} or set {OPENVIKING_CONFIG_ENV}.\n" + f"Please create {default_path_user} or {default_path_system}, or set {OPENVIKING_CONFIG_ENV}.\n" f"See: https://openviking.dev/docs/guides/configuration" ) diff --git a/openviking_cli/utils/config/__init__.py b/openviking_cli/utils/config/__init__.py index ee3064f4..01737a20 100644 --- a/openviking_cli/utils/config/__init__.py +++ b/openviking_cli/utils/config/__init__.py @@ -2,14 +2,17 @@ # SPDX-License-Identifier: Apache-2.0 from .agfs_config import AGFSConfig from .config_loader import ( + load_json_config, + require_config, + resolve_config_path, +) +from .consts import ( DEFAULT_CONFIG_DIR, DEFAULT_OV_CONF, DEFAULT_OVCLI_CONF, OPENVIKING_CLI_CONFIG_ENV, OPENVIKING_CONFIG_ENV, - load_json_config, - require_config, - resolve_config_path, + SYSTEM_CONFIG_DIR, ) from .embedding_config import EmbeddingConfig from .log_config import LogConfig @@ -42,7 +45,7 @@ __all__ = [ "AGFSConfig", - "DEFAULT_CONFIG_DIR", + "SYSTEM_CONFIG_DIR", "DEFAULT_OV_CONF", "DEFAULT_OVCLI_CONF", "EmbeddingConfig", diff --git a/openviking_cli/utils/config/config_loader.py b/openviking_cli/utils/config/config_loader.py index 177763ff..8e72a6bb 100644 --- a/openviking_cli/utils/config/config_loader.py +++ b/openviking_cli/utils/config/config_loader.py @@ -2,10 +2,11 @@ # SPDX-License-Identifier: Apache-2.0 """Configuration file loading utilities. -Provides a three-level resolution chain for locating config files: +Provides a four-level resolution chain for locating config files: 1. Explicit path (constructor parameter / --config) 2. Environment variable 3. Default path (~/.openviking/) + 4. System path (/etc/openviking/) """ import json @@ -13,13 +14,10 @@ from pathlib import Path from typing import Any, Dict, Optional -DEFAULT_CONFIG_DIR = Path.home() / ".openviking" - -OPENVIKING_CONFIG_ENV = "OPENVIKING_CONFIG_FILE" -OPENVIKING_CLI_CONFIG_ENV = "OPENVIKING_CLI_CONFIG_FILE" - -DEFAULT_OV_CONF = "ov.conf" -DEFAULT_OVCLI_CONF = "ovcli.conf" +from .consts import ( + DEFAULT_CONFIG_DIR, + SYSTEM_CONFIG_DIR, +) def resolve_config_path( @@ -27,12 +25,13 @@ def resolve_config_path( env_var: str, default_filename: str, ) -> Optional[Path]: - """Resolve a config file path using the three-level chain. + """Resolve a config file path using the four-level chain. Resolution order: 1. ``explicit_path`` (if provided and exists) 2. Path from environment variable ``env_var`` 3. ``~/.openviking/`` + 4. ``/etc/openviking/`` Returns: Path to the config file, or None if not found at any level. @@ -52,11 +51,16 @@ def resolve_config_path( return p return None - # Level 3: default directory + # Level 3: default directory (~/.openviking) p = DEFAULT_CONFIG_DIR / default_filename if p.exists(): return p + # Level 4: system directory (/etc/openviking) + p = SYSTEM_CONFIG_DIR / default_filename + if p.exists(): + return p + return None @@ -78,6 +82,7 @@ def load_json_config(path: Path) -> Dict[str, Any]: with open(path, "r", encoding="utf-8") as f: try: + print(f"Loading config file: {path}") return json.load(f) except json.JSONDecodeError as e: raise ValueError(f"Invalid JSON in config file {path}: {e}") from e @@ -105,10 +110,11 @@ def require_config( """ path = resolve_config_path(explicit_path, env_var, default_filename) if path is None: - default_path = DEFAULT_CONFIG_DIR / default_filename + default_path_user = DEFAULT_CONFIG_DIR / default_filename + default_path_system = SYSTEM_CONFIG_DIR / default_filename raise FileNotFoundError( f"OpenViking {purpose} configuration file not found.\n" - f"Please create {default_path} or set {env_var}.\n" + f"Please create {default_path_user} or {default_path_system}, or set {env_var}.\n" f"See: https://openviking.dev/docs/guides/configuration" ) return load_json_config(path) diff --git a/openviking_cli/utils/config/consts.py b/openviking_cli/utils/config/consts.py new file mode 100644 index 00000000..74e19204 --- /dev/null +++ b/openviking_cli/utils/config/consts.py @@ -0,0 +1,14 @@ +# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd. +# SPDX-License-Identifier: Apache-2.0 +"""Configuration constants for OpenViking.""" + +from pathlib import Path + +DEFAULT_CONFIG_DIR = Path.home() / ".openviking" +SYSTEM_CONFIG_DIR = Path("/etc/openviking") + +OPENVIKING_CONFIG_ENV = "OPENVIKING_CONFIG_FILE" +OPENVIKING_CLI_CONFIG_ENV = "OPENVIKING_CLI_CONFIG_FILE" + +DEFAULT_OV_CONF = "ov.conf" +DEFAULT_OVCLI_CONF = "ovcli.conf" diff --git a/openviking_cli/utils/config/open_viking_config.py b/openviking_cli/utils/config/open_viking_config.py index b78020b4..72342563 100644 --- a/openviking_cli/utils/config/open_viking_config.py +++ b/openviking_cli/utils/config/open_viking_config.py @@ -9,10 +9,12 @@ from openviking_cli.session.user_id import UserIdentifier -from .config_loader import ( +from .config_loader import resolve_config_path +from .consts import ( + DEFAULT_CONFIG_DIR, DEFAULT_OV_CONF, OPENVIKING_CONFIG_ENV, - resolve_config_path, + SYSTEM_CONFIG_DIR, ) from .embedding_config import EmbeddingConfig from .log_config import LogConfig @@ -168,7 +170,8 @@ class OpenVikingConfigSingleton: 1. Explicit path passed to initialize() 2. OPENVIKING_CONFIG_FILE environment variable 3. ~/.openviking/ov.conf - 4. Error with clear guidance + 4. /etc/openviking/ov.conf + 5. Error with clear guidance """ _instance: Optional[OpenVikingConfig] = None @@ -187,12 +190,11 @@ def get_instance(cls) -> OpenVikingConfig: if config_path is not None: cls._instance = cls._load_from_file(str(config_path)) else: - from .config_loader import DEFAULT_CONFIG_DIR - - default_path = DEFAULT_CONFIG_DIR / DEFAULT_OV_CONF + default_path_user = DEFAULT_CONFIG_DIR / DEFAULT_OV_CONF + default_path_system = SYSTEM_CONFIG_DIR / DEFAULT_OV_CONF raise FileNotFoundError( f"OpenViking configuration file not found.\n" - f"Please create {default_path} or set {OPENVIKING_CONFIG_ENV}.\n" + f"Please create {default_path_user} or {default_path_system}, or set {OPENVIKING_CONFIG_ENV}.\n" f"See: https://openviking.dev/docs/guides/configuration" ) return cls._instance @@ -217,12 +219,11 @@ def initialize( if path is not None: cls._instance = cls._load_from_file(str(path)) else: - from .config_loader import DEFAULT_CONFIG_DIR - - default_path = DEFAULT_CONFIG_DIR / DEFAULT_OV_CONF + default_path_user = DEFAULT_CONFIG_DIR / DEFAULT_OV_CONF + default_path_system = SYSTEM_CONFIG_DIR / DEFAULT_OV_CONF raise FileNotFoundError( f"OpenViking configuration file not found.\n" - f"Please create {default_path} or set {OPENVIKING_CONFIG_ENV}.\n" + f"Please create {default_path_user} or {default_path_system}, or set {OPENVIKING_CONFIG_ENV}.\n" f"See: https://openviking.dev/docs/guides/configuration" ) return cls._instance