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
15 changes: 9 additions & 6 deletions openviking/server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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"
)

Expand Down
11 changes: 7 additions & 4 deletions openviking_cli/utils/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -42,7 +45,7 @@

__all__ = [
"AGFSConfig",
"DEFAULT_CONFIG_DIR",
"SYSTEM_CONFIG_DIR",
"DEFAULT_OV_CONF",
"DEFAULT_OVCLI_CONF",
"EmbeddingConfig",
Expand Down
30 changes: 18 additions & 12 deletions openviking_cli/utils/config/config_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,36 @@
# 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
import os
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(
explicit_path: Optional[str],
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/<default_filename>``
4. ``/etc/openviking/<default_filename>``

Returns:
Path to the config file, or None if not found at any level.
Expand All @@ -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


Expand All @@ -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
Expand Down Expand Up @@ -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)
14 changes: 14 additions & 0 deletions openviking_cli/utils/config/consts.py
Original file line number Diff line number Diff line change
@@ -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"
23 changes: 12 additions & 11 deletions openviking_cli/utils/config/open_viking_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down