Compare commits
6 Commits
fix/issue-
...
fix/674-pi
| Author | SHA1 | Date | |
|---|---|---|---|
| bca52ea61e | |||
| d120526244 | |||
| 8596ff761b | |||
| 7553fd4f3e | |||
| 71082fe06f | |||
| 6d678e938e |
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Full Nostr agent-to-agent communication demo - FINAL WORKING
|
||||
"""
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Soul Eval Gate — The Conscience of the Training Pipeline
|
||||
|
||||
@@ -25,11 +26,9 @@ Usage:
|
||||
result = evaluate_candidate(scores_path, baseline_path, candidate_id)
|
||||
"""
|
||||
|
||||
import glob
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from datetime import datetime, timezone
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
@@ -65,10 +64,6 @@ MAX_METRIC_REGRESSION = -0.15
|
||||
# Default paths
|
||||
DEFAULT_GATE_DIR = Path.home() / ".timmy" / "training-data" / "eval-gates"
|
||||
|
||||
# Gate file rotation settings (fixes #628: hash dedup growth)
|
||||
GATE_FILE_MAX_AGE_DAYS = 7 # Delete gate files older than this
|
||||
GATE_FILE_MAX_COUNT = 50 # Keep at most this many gate files (excluding latest)
|
||||
|
||||
|
||||
def evaluate_candidate(
|
||||
scores_path: str | Path,
|
||||
@@ -245,9 +240,6 @@ def evaluate_candidate(
|
||||
latest_file = gate_dir / "eval_gate_latest.json"
|
||||
latest_file.write_text(json.dumps(result, indent=2))
|
||||
|
||||
# Rotate old gate files to prevent unbounded growth (#628)
|
||||
_rotate_gate_files(gate_dir)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -296,58 +288,6 @@ def _find_category_score(
|
||||
return None
|
||||
|
||||
|
||||
def _rotate_gate_files(gate_dir: Path) -> int:
|
||||
"""Rotate and clean up old eval gate files.
|
||||
|
||||
Prevents unbounded growth of the gate file directory by:
|
||||
1. Deleting files older than GATE_FILE_MAX_AGE_DAYS
|
||||
2. Keeping at most GATE_FILE_MAX_COUNT historical files
|
||||
3. Always preserving eval_gate_latest.json
|
||||
|
||||
Returns the number of files deleted.
|
||||
"""
|
||||
if not gate_dir.exists():
|
||||
return 0
|
||||
|
||||
deleted = 0
|
||||
now = datetime.now(timezone.utc)
|
||||
cutoff = now - timedelta(days=GATE_FILE_MAX_AGE_DAYS)
|
||||
|
||||
# Find all eval_gate_*.json files, excluding latest
|
||||
pattern = str(gate_dir / "eval_gate_*.json")
|
||||
all_files = glob.glob(pattern)
|
||||
gate_files = [f for f in all_files if not f.endswith("eval_gate_latest.json")]
|
||||
|
||||
# Sort by modification time (oldest first)
|
||||
gate_files.sort(key=lambda f: os.path.getmtime(f))
|
||||
|
||||
for filepath in gate_files:
|
||||
try:
|
||||
mtime = datetime.fromtimestamp(os.path.getmtime(filepath), tz=timezone.utc)
|
||||
|
||||
# Delete if older than max age
|
||||
if mtime < cutoff:
|
||||
os.remove(filepath)
|
||||
deleted += 1
|
||||
continue
|
||||
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
# Enforce max count (delete oldest first)
|
||||
remaining = [f for f in gate_files if os.path.exists(f)]
|
||||
if len(remaining) > GATE_FILE_MAX_COUNT:
|
||||
excess = remaining[:len(remaining) - GATE_FILE_MAX_COUNT]
|
||||
for filepath in excess:
|
||||
try:
|
||||
os.remove(filepath)
|
||||
deleted += 1
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return deleted
|
||||
|
||||
|
||||
# ── CLI ──────────────────────────────────────────────────────────────
|
||||
|
||||
def main():
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
from hermes_tools import browser_navigate, browser_vision
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
from hermes_tools import browser_navigate, browser_vision
|
||||
|
||||
|
||||
@@ -117,14 +117,26 @@ is_pipeline_complete() {
|
||||
local pipeline="$1"
|
||||
python3 -c "
|
||||
import json, os
|
||||
from datetime import datetime, timezone, timedelta
|
||||
path = '$STATE_FILE'
|
||||
if not os.path.exists(path):
|
||||
print('false')
|
||||
else:
|
||||
with open(path) as f:
|
||||
d = json.load(f)
|
||||
state = d.get('$pipeline', {}).get('state', 'not_started')
|
||||
print('true' if state == 'complete' else 'false')
|
||||
entry = d.get('$pipeline', {})
|
||||
state = entry.get('state', 'not_started')
|
||||
if state != 'complete':
|
||||
print('false')
|
||||
else:
|
||||
# Check staleness: complete from a previous day is stale
|
||||
updated = entry.get('updated', '')
|
||||
try:
|
||||
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
|
||||
is_today = (datetime.now(timezone.utc) - t) < timedelta(hours=24)
|
||||
print('true' if is_today else 'false')
|
||||
except Exception:
|
||||
print('false')
|
||||
" 2>/dev/null || echo false
|
||||
}
|
||||
|
||||
@@ -132,17 +144,64 @@ is_pipeline_running() {
|
||||
local pipeline="$1"
|
||||
python3 -c "
|
||||
import json, os
|
||||
from datetime import datetime, timezone, timedelta
|
||||
path = '$STATE_FILE'
|
||||
if not os.path.exists(path):
|
||||
print('false')
|
||||
else:
|
||||
with open(path) as f:
|
||||
d = json.load(f)
|
||||
state = d.get('$pipeline', {}).get('state', 'not_started')
|
||||
print('true' if state == 'running' else 'false')
|
||||
entry = d.get('$pipeline', {})
|
||||
state = entry.get('state', 'not_started')
|
||||
if state != 'running':
|
||||
print('false')
|
||||
else:
|
||||
# Running for >6 hours is likely crashed
|
||||
updated = entry.get('updated', '')
|
||||
try:
|
||||
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
|
||||
stale = (datetime.now(timezone.utc) - t) > timedelta(hours=6)
|
||||
print('false' if stale else 'true')
|
||||
except Exception:
|
||||
print('true')
|
||||
" 2>/dev/null || echo false
|
||||
}
|
||||
|
||||
|
||||
reset_stale_states() {
|
||||
python3 -c "
|
||||
import json, os
|
||||
from datetime import datetime, timezone, timedelta
|
||||
path = '\$STATE_FILE'
|
||||
if not os.path.exists(path):
|
||||
exit(0)
|
||||
with open(path) as f:
|
||||
d = json.load(f)
|
||||
stale = []
|
||||
for name, entry in list(d.items()):
|
||||
if not isinstance(entry, dict) or 'state' not in entry:
|
||||
continue
|
||||
state = entry['state']
|
||||
updated = entry.get('updated', '')
|
||||
try:
|
||||
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
|
||||
except Exception:
|
||||
stale.append(name)
|
||||
continue
|
||||
age = datetime.now(timezone.utc) - t
|
||||
if state in ('complete', 'failed') and age > timedelta(hours=24):
|
||||
stale.append(name)
|
||||
elif state == 'running' and age > timedelta(hours=6):
|
||||
stale.append(name)
|
||||
for name in stale:
|
||||
del d[name]
|
||||
if stale:
|
||||
with open(path, 'w') as f:
|
||||
json.dump(d, f, indent=2)
|
||||
print('Reset stale pipelines: ' + ', '.join(stale))
|
||||
" 2>/dev/null
|
||||
}
|
||||
|
||||
check_dependency() {
|
||||
local dep="$1"
|
||||
if [[ "$dep" == "none" ]]; then
|
||||
@@ -310,22 +369,44 @@ main() {
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Reset stale pipeline states from previous days
|
||||
reset_stale_states
|
||||
|
||||
# Check 5: Pipeline status
|
||||
if [[ "$mode" == "--status" ]]; then
|
||||
echo -e "${CYAN}Pipeline Status:${NC}"
|
||||
echo "────────────────────────────────────────────────────"
|
||||
for entry in "${PIPELINES[@]}"; do
|
||||
IFS='|' read -r name script max_tokens dep <<< "$entry"
|
||||
local state=$(python3 -c "
|
||||
local state_info=$(python3 -c "
|
||||
import json, os
|
||||
from datetime import datetime, timezone, timedelta
|
||||
path = '$STATE_FILE'
|
||||
if not os.path.exists(path):
|
||||
print('not_started')
|
||||
print('not_started|')
|
||||
else:
|
||||
with open(path) as f:
|
||||
d = json.load(f)
|
||||
print(d.get('$name', {}).get('state', 'not_started'))
|
||||
" 2>/dev/null || echo "not_started")
|
||||
entry = d.get('$name', {})
|
||||
state = entry.get('state', 'not_started')
|
||||
updated = entry.get('updated', '')
|
||||
stale = ''
|
||||
try:
|
||||
t = datetime.fromisoformat(updated.replace('Z', '+00:00'))
|
||||
age = datetime.now(timezone.utc) - t
|
||||
if state in ('complete', 'failed') and age > timedelta(hours=24):
|
||||
stale = 'stale'
|
||||
elif state == 'running' and age > timedelta(hours=6):
|
||||
stale = 'stale'
|
||||
except Exception:
|
||||
pass
|
||||
print(state + '|' + stale)
|
||||
" 2>/dev/null || echo "not_started|")
|
||||
|
||||
local state="${state_info%%|*}"
|
||||
local stale="${state_info##*|}"
|
||||
local suffix=""
|
||||
[[ -n "$stale" ]] && suffix=" (stale)"
|
||||
|
||||
local color=$NC
|
||||
case "$state" in
|
||||
@@ -333,7 +414,7 @@ else:
|
||||
complete) color=$GREEN ;;
|
||||
failed) color=$RED ;;
|
||||
esac
|
||||
printf " %-25s %b%s%b (max: %s tokens, dep: %s)\n" "$name" "$color" "$state" "$NC" "$max_tokens" "$dep"
|
||||
printf " %-25s %b%s%s%b (max: %s tokens, dep: %s)\n" "$name" "$color" "$state" "$suffix" "$NC" "$max_tokens" "$dep"
|
||||
done
|
||||
echo "────────────────────────────────────────────────────"
|
||||
echo " Budget: $budget / $TOKEN_DAILY_LIMIT tokens remaining"
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
from hermes_tools import browser_navigate, browser_vision
|
||||
|
||||
|
||||
Reference in New Issue
Block a user