File size: 2,838 Bytes
399b80c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
"""Host-agent config auto-detection.

Public API consumed by other OpenSpace subsystems (cloud, mcp_server, …):

  - ``build_llm_kwargs``          β€” resolve LLM credentials
  - ``build_grounding_config_path`` β€” resolve grounding config
  - ``read_host_mcp_env``         β€” host-agnostic skill env reader
  - ``get_openai_api_key``        β€” OpenAI key resolution (multi-host)

Internal / legacy re-exports (prefer the generic names above):

  - ``read_nanobot_mcp_env``      β€” nanobot-specific, kept for backward compat
  - ``try_read_nanobot_config``

Supported host agents:

  - **nanobot** β€” ``~/.nanobot/config.json``  (``tools.mcpServers.openspace.env``)
  - **openclaw** β€” ``~/.openclaw/openclaw.json``  (``skills.entries.openspace.env``)
"""

import logging
from typing import Dict, Optional

from openspace.host_detection.resolver import build_llm_kwargs, build_grounding_config_path
from openspace.host_detection.nanobot import (
    get_openai_api_key as _nanobot_get_openai_api_key,
    read_nanobot_mcp_env,
    try_read_nanobot_config,
)
from openspace.host_detection.openclaw import (
    get_openclaw_openai_api_key as _openclaw_get_openai_api_key,
    is_openclaw_host,
    read_openclaw_skill_env,
)

logger = logging.getLogger("openspace.host_detection")


def read_host_mcp_env() -> Dict[str, str]:
    """Read the OpenSpace env block from the current host agent config.

    Resolution order:
      1. nanobot β€” ``tools.mcpServers.openspace.env``
      2. openclaw β€” ``skills.entries.openspace.env``
      3. Empty dict (no host detected)

    Callers (e.g. ``cloud.auth``) use this single entry point and never
    need to know which host agent is active.
    """
    # Try nanobot first (most common deployment)
    env = read_nanobot_mcp_env()
    if env:
        return env

    # Try openclaw
    env = read_openclaw_skill_env("openspace")
    if env:
        logger.debug("read_host_mcp_env: resolved from OpenClaw config")
        return env

    return {}


def get_openai_api_key() -> Optional[str]:
    """Get OpenAI API key for embedding generation (multi-host).

    Resolution:
      1. ``OPENAI_API_KEY`` env var  (checked inside nanobot reader)
      2. nanobot config ``providers.openai.apiKey``
      3. openclaw config ``skills.entries.openspace.env.OPENAI_API_KEY``
      4. None
    """
    # nanobot reader already checks OPENAI_API_KEY env var first
    key = _nanobot_get_openai_api_key()
    if key:
        return key
    return _openclaw_get_openai_api_key()


__all__ = [
    "build_llm_kwargs",
    "build_grounding_config_path",
    "get_openai_api_key",
    "read_host_mcp_env",
    # legacy re-exports
    "read_nanobot_mcp_env",
    "try_read_nanobot_config",
    # openclaw-specific (for direct use if needed)
    "is_openclaw_host",
    "read_openclaw_skill_env",
]