-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathconsolidate.py
More file actions
125 lines (103 loc) · 4.64 KB
/
Copy pathconsolidate.py
File metadata and controls
125 lines (103 loc) · 4.64 KB
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env python3
"""consolidate.py — backwards-compat shim for the Hades Nightly cron.
The Hades Nightly cron at 9am (job `cfb065b056ac`) has its prompt
hardcoded to call `python3 consolidate.py`. The original
consolidate.py was removed in some earlier cleanup; this file is a
replacement that delegates to the modern `scripts/hades` shim so
tonight's 9am run doesn't fail at step 1.
Brittleness fix #1 (2026-06-03): the cron prompt references a
non-existent file (`consolidate.py` was deleted, the live entry point
is `scripts/hades` via the package refactor). This shim gives the
cron something to call without forcing a cron-prompt rewrite.
If you're editing the cron prompt, you can replace the
`python3 consolidate.py` line with `python3 scripts/hades` and
delete this file. Until then, this shim keeps the existing prompt
working.
For modern callers, prefer the explicit flags:
python3 scripts/hades --health
python3 scripts/hades --distill
python3 scripts/hades --archive
python3 scripts/hades # full sweep
"""
from __future__ import annotations
import os
import subprocess
import sys
from pathlib import Path
# Resolve scripts/hades relative to this file
HERE = Path(__file__).resolve().parent
SHIM = HERE / "scripts" / "hades"
def _venv_python() -> str:
"""Path to the hermes-agent venv python (has chromadb installed).
The nightly Hades cron calls `python3 consolidate.py` from the
cron subshell, which resolves `python3` to /usr/bin/python3
(system Python, no third-party packages). The embed phase then
fails silently with `ModuleNotFoundError: No module named
'chromadb'`, the orchestrator catches the exception, and the
9:15am notif rubber-stamps success. Self-heal by re-execing
under the venv interpreter that has chromadb available.
"""
venv = Path("/home/konan/.hermes/hermes-agent/venv/bin/python3")
if venv.is_file():
return str(venv)
return sys.executable
def _has_chromadb() -> bool:
"""Best-effort check that the current interpreter can import chromadb.
Returns True if importable, False otherwise. Used to decide
whether to re-exec under the venv python.
"""
try:
import chromadb # noqa: F401
return True
except Exception:
return False
def main() -> int:
if not SHIM.exists():
print(f"ERROR: {SHIM} not found — was the package refactored?", file=sys.stderr)
return 1
# Self-heal: if the current interpreter can't import chromadb,
# re-exec under the hermes-agent venv python. The nightly cron
# resolves bare `python3` to /usr/bin/python3, which lacks
# chromadb. The venv at ~/.hermes/hermes-agent/venv has it.
interpreter = sys.executable
if not _has_chromadb():
venv_py = _venv_python()
if venv_py != sys.executable and Path(venv_py).is_file():
print(
f"[consolidate.py] chromadb not importable in "
f"{sys.executable}; re-execing under {venv_py}",
file=sys.stderr,
)
cmd = [venv_py, str(Path(__file__).resolve())] + sys.argv[1:]
return subprocess.run(cmd).returncode
# Default behavior: full sweep. If the cron ever needs
# granular control, pass flags through.
cmd = [interpreter, str(SHIM)]
# Pass through any flags the caller provided
cmd.extend(sys.argv[1:])
# Default a 60-minute hard timeout (was 25 min). The previous
# 1500s total → 500s/phase was too tight once the embed phase
# started actually doing work (~23s/file on local ollama means
# 30 files takes ~12 min, leaving 38 min unused in the 25-min
# budget that triggered the per-phase alarm). The new 3600s
# → 1200s/phase is sized for HADES_EMBED_MAX_FILES=150
# (≈58 min worst case) with headroom for slow files.
env = os.environ.copy()
if "--timeout" not in sys.argv:
cmd.extend(["--timeout", "3600"])
# Raise the per-phase file cap from 30 → 150 to drain the
# ~185-file backlog in ~2 nightly runs. Read by
# ``hades.embed.embed_missing_files()`` (default 30 if unset).
# Manual callers can override via env var or by passing the
# ``max_files`` arg to ``embed_missing_files()`` directly.
env.setdefault("HADES_EMBED_MAX_FILES", "150")
# Delegation log goes to stderr so --json consumers can pipe stdout
print(f"[consolidate.py] Delegating to: {' '.join(cmd)}", file=sys.stderr)
print(
f"[consolidate.py] HADES_EMBED_MAX_FILES={env['HADES_EMBED_MAX_FILES']}",
file=sys.stderr,
)
result = subprocess.run(cmd, env=env)
return result.returncode
if __name__ == "__main__":
sys.exit(main())