|
3 | 3 | # Idempotent: safe to re-run. Source of truth is this repo's agent/ dir. |
4 | 4 | # |
5 | 5 | # Configures: |
6 | | -# - model: existing Azure OpenAI gpt-5.4 via its OpenAI-compatible v1 endpoint |
| 6 | +# - model: from DEEPSQL_CHAT_* (or legacy AZURE_OPENAI_*) via OpenAI-compatible endpoint |
7 | 7 | # - mcp_servers.deepsql: the repo's DeepSQL MCP server (read-only DBA tools) |
8 | 8 | # - skills.external_dirs: this repo's agent/skills (source of truth) |
9 | 9 | # - approvals.mode: smart |
10 | 10 | # - SOUL.md: the DBA persona |
11 | 11 | # - disables host-affecting toolsets (terminal/file/code/browser/computer_use) |
12 | 12 | # |
13 | 13 | # Secrets are read from the environment (or the repo .env), never committed: |
14 | | -# AZURE_OPENAI_KEY, AZURE_OPENAI_ENDPOINT (endpoint defaults to the repo value) |
| 14 | +# DEEPSQL_CHAT_API_KEY, DEEPSQL_CHAT_ENDPOINT, DEEPSQL_CHAT_MODEL |
| 15 | +# (legacy fallback: AZURE_OPENAI_KEY, AZURE_OPENAI_ENDPOINT) |
15 | 16 | # |
16 | 17 | # Upstream note: HERMES_HOME / hermes-agent / hermes CLI are contracts of the |
17 | 18 | # Nous Hermes Agent runtime this customization runs on — do not rename those. |
18 | 19 | set -euo pipefail |
19 | 20 |
|
20 | 21 | REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" |
21 | | -HERMES_HOME="${HERMES_HOME:-$HOME/.hermes}" |
| 22 | +# Reject a nested profile home inherited from a live Hermes process. |
| 23 | +if [[ "${HERMES_HOME:-}" == */profiles/* ]]; then |
| 24 | + unset HERMES_HOME |
| 25 | +fi |
| 26 | +HERMES_HOME="${DEEPSQL_HERMES_HOME:-${HERMES_HOME:-$HOME/.hermes}}" |
22 | 27 | AGENT_DIR="${HERMES_AGENT_DIR:-$HERMES_HOME/hermes-agent}" |
23 | | -VENV_PY="$AGENT_DIR/.venv/bin/python" |
24 | 28 |
|
25 | | -# Load repo .env for Azure creds if not already in the environment. |
| 29 | +# Prefer the same interpreter order as scripts/self-host/setup-agent.sh |
| 30 | +if [[ -x "$AGENT_DIR/venv/bin/python" ]]; then |
| 31 | + VENV_PY="$AGENT_DIR/venv/bin/python" |
| 32 | +elif [[ -x "$AGENT_DIR/.venv/bin/python" ]]; then |
| 33 | + VENV_PY="$AGENT_DIR/.venv/bin/python" |
| 34 | +else |
| 35 | + echo "Agent venv not found under $AGENT_DIR — run scripts/self-host/setup-agent.sh first." >&2 |
| 36 | + exit 1 |
| 37 | +fi |
| 38 | + |
| 39 | +# Load repo .env for LLM creds if not already in the environment. |
26 | 40 | if [[ -f "$REPO_ROOT/.env" ]]; then set -a; . "$REPO_ROOT/.env"; set +a; fi |
27 | | -: "${AZURE_OPENAI_KEY:?Set AZURE_OPENAI_KEY (or add it to repo .env)}" |
28 | | -AZURE_ENDPOINT_HOST="$(printf '%s' "${AZURE_OPENAI_ENDPOINT:-https://your-resource.cognitiveservices.azure.com/}" | sed -E 's#https?://##; s#/.*##; s#\.cognitiveservices\.azure\.com#.openai.azure.com#')" |
29 | | -BASE_URL="https://${AZURE_ENDPOINT_HOST}/openai/v1" |
30 | 41 |
|
31 | | -[[ -x "$VENV_PY" ]] || { echo "Agent venv not found at $VENV_PY — install the agent runtime first."; exit 1; } |
| 42 | +# Prefer the same BYO-LLM vars the Spring backend uses. Fall back to legacy |
| 43 | +# AZURE_OPENAI_* for older checkouts. |
| 44 | +API_KEY="${DEEPSQL_CHAT_API_KEY:-${AZURE_OPENAI_KEY:-}}" |
| 45 | +ENDPOINT="${DEEPSQL_CHAT_ENDPOINT:-${AZURE_OPENAI_ENDPOINT:-}}" |
| 46 | +MODEL="${DEEPSQL_CHAT_MODEL:-gpt-5.4}" |
| 47 | + |
| 48 | +if [[ -z "$API_KEY" ]]; then |
| 49 | + echo "Error: set DEEPSQL_CHAT_API_KEY (or AZURE_OPENAI_KEY) in the environment or $REPO_ROOT/.env" >&2 |
| 50 | + exit 1 |
| 51 | +fi |
| 52 | +if [[ -z "$ENDPOINT" ]]; then |
| 53 | + echo "Error: set DEEPSQL_CHAT_ENDPOINT (or AZURE_OPENAI_ENDPOINT)." >&2 |
| 54 | + exit 1 |
| 55 | +fi |
| 56 | + |
| 57 | +# Normalize to an OpenAI-compatible …/openai/v1 or …/v1 base URL. |
| 58 | +# Azure Cognitive Services / Azure OpenAI hosts need /openai/v1; plain OpenAI |
| 59 | +# and OpenAI-compatible servers already expose /v1. |
| 60 | +normalize_base_url() { |
| 61 | + local ep="$1" |
| 62 | + ep="${ep%/}" |
| 63 | + if [[ "$ep" == *"/openai/v1" || "$ep" == *"/v1" ]]; then |
| 64 | + printf '%s' "$ep" |
| 65 | + return |
| 66 | + fi |
| 67 | + if [[ "$ep" == *".cognitiveservices.azure.com"* || "$ep" == *".openai.azure.com"* || "$ep" == *".azure-api.net"* ]]; then |
| 68 | + printf '%s/openai/v1' "$ep" |
| 69 | + return |
| 70 | + fi |
| 71 | + printf '%s/v1' "$ep" |
| 72 | +} |
| 73 | +BASE_URL="$(normalize_base_url "$ENDPOINT")" |
| 74 | + |
| 75 | +BACKEND_PORT="${DEEPSQL_BACKEND_PORT:-8080}" |
32 | 76 |
|
33 | 77 | echo "→ Repo: $REPO_ROOT" |
34 | 78 | echo "→ Agent home: $HERMES_HOME" |
35 | | -echo "→ Model base: $BASE_URL" |
| 79 | +echo "→ Model: $MODEL @ $BASE_URL" |
36 | 80 |
|
37 | | -# Deep-merge the DBA config blocks into ~/.hermes/config.yaml (PyYAML ships with the agent). |
38 | | -REPO_ROOT="$REPO_ROOT" BASE_URL="$BASE_URL" AZURE_OPENAI_KEY="$AZURE_OPENAI_KEY" \ |
39 | | -HERMES_HOME="$HERMES_HOME" "$VENV_PY" - <<'PY' |
| 81 | +REPO_ROOT="$REPO_ROOT" BASE_URL="$BASE_URL" API_KEY="$API_KEY" MODEL="$MODEL" \ |
| 82 | +BACKEND_PORT="$BACKEND_PORT" HERMES_HOME="$HERMES_HOME" "$VENV_PY" - <<'PY' |
40 | 83 | import os, yaml, pathlib |
41 | 84 | home = pathlib.Path(os.environ["HERMES_HOME"]); repo = os.environ["REPO_ROOT"] |
42 | 85 | cfg_path = home / "config.yaml" |
43 | 86 | cfg = yaml.safe_load(cfg_path.read_text()) if cfg_path.exists() else {} |
44 | 87 | cfg = cfg or {} |
45 | 88 | cfg["model"] = { |
46 | | - "default": "gpt-5.4", "provider": "custom", |
47 | | - "base_url": os.environ["BASE_URL"], "api_key": os.environ["AZURE_OPENAI_KEY"], |
48 | | - "api_mode": "chat_completions", "context_length": 272000, |
| 89 | + "default": os.environ["MODEL"], |
| 90 | + "provider": "custom", |
| 91 | + "base_url": os.environ["BASE_URL"], |
| 92 | + "api_key": os.environ["API_KEY"], |
| 93 | + "api_mode": "chat_completions", |
| 94 | + "context_length": 272000, |
| 95 | +} |
| 96 | +cfg.setdefault("providers", {})["custom"] = { |
| 97 | + "base_url": os.environ["BASE_URL"], |
| 98 | + "api_key": os.environ["API_KEY"], |
| 99 | +} |
| 100 | +# Keep an existing DEEPSQL_AUTH_TOKEN if a prior setup-agent run wrote one into |
| 101 | +# the root config; otherwise leave token unset — setup-agent.sh provisions the |
| 102 | +# per-user profile with a minted token. |
| 103 | +existing_env = ((cfg.get("mcp_servers") or {}).get("deepsql") or {}).get("env") or {} |
| 104 | +mcp_env = { |
| 105 | + "DEEPSQL_API_BASE_URL": f"http://localhost:{os.environ['BACKEND_PORT']}/api/", |
| 106 | + "DEEPSQL_MCP_USER_ID": existing_env.get("DEEPSQL_MCP_USER_ID", "deepsql-agent"), |
| 107 | + "DEEPSQL_MCP_PROJECT_ID": existing_env.get("DEEPSQL_MCP_PROJECT_ID", "deepsql-agent"), |
49 | 108 | } |
| 109 | +if existing_env.get("DEEPSQL_AUTH_TOKEN"): |
| 110 | + mcp_env["DEEPSQL_AUTH_TOKEN"] = existing_env["DEEPSQL_AUTH_TOKEN"] |
50 | 111 | cfg.setdefault("mcp_servers", {})["deepsql"] = { |
51 | 112 | "command": "node", |
52 | 113 | "args": [f"{repo}/mcp/deepsql-phase1-server.js"], |
53 | | - "env": {"DEEPSQL_API_BASE_URL": "http://localhost:8080/api/", |
54 | | - "DEEPSQL_MCP_USER_ID": "deepsql-agent", "DEEPSQL_MCP_PROJECT_ID": "deepsql-agent"}, |
| 114 | + "env": mcp_env, |
55 | 115 | } |
56 | 116 | cfg.setdefault("skills", {})["external_dirs"] = [f"{repo}/agent/skills"] |
57 | 117 | cfg.setdefault("approvals", {})["mode"] = "smart" |
|
63 | 123 | cp "$REPO_ROOT/agent/SOUL.md" "$HERMES_HOME/SOUL.md" |
64 | 124 | echo " SOUL.md installed" |
65 | 125 |
|
66 | | -# Scope to a read-only sandbox: disable host-affecting toolsets. |
67 | 126 | ( cd "$AGENT_DIR" && UV_NO_CONFIG=1 "$VENV_PY" -m hermes_cli.main tools disable \ |
68 | 127 | terminal file code_execution browser computer_use image_gen tts vision web delegation cronjob \ |
69 | 128 | >/dev/null 2>&1 ) || echo " (toolset disable skipped — disable manually with 'hermes tools disable ...')" |
70 | 129 | echo " host toolsets disabled (read-only deepsql + memory/todo/skills remain)" |
71 | 130 |
|
72 | | -echo "✓ DeepSQL Agent customization installed. Verify: (cd $AGENT_DIR && uv run hermes mcp test deepsql)" |
| 131 | +echo "✓ DeepSQL Agent customization installed." |
| 132 | +echo " Verify: (cd $AGENT_DIR && uv run hermes mcp test deepsql)" |
| 133 | +echo " Or run: scripts/self-host/setup-agent.sh (starts webui + provisions MCP token)" |
0 commit comments