mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-05-23 12:55:26 +00:00
- trainer.rs: Daily Discovery Brain Training module with altruistic principles by rUv. Fetches NASA, USGS, NOAA, OpenAlex APIs and runs anomaly detection for automated brain training. - Wire trainer into mcp-brain-server lib.rs - Fix train_brain.sh: add Authorization Bearer header for brain API - Successfully trained pi.ruv.io: 897→953 memories, +25,832 graph edges, knowledge velocity activated (0→56) https://claude.ai/code/session_01UWE22wnsZRSHKhT4h4Axby
270 lines
7.9 KiB
Bash
Executable file
270 lines
7.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
#
|
|
# train_brain.sh - Push discovery JSON files to pi.ruv.io brain API
|
|
#
|
|
# Reads all *_discoveries.json files from the discoveries directory,
|
|
# extracts each discovery entry, and POSTs it as a memory to the
|
|
# brain API using the challenge-nonce authentication flow.
|
|
#
|
|
# Usage: ./scripts/train_brain.sh [discoveries_dir]
|
|
#
|
|
set -euo pipefail
|
|
|
|
DISCOVERIES_DIR="${1:-/home/user/RuVector/examples/data/discoveries}"
|
|
BRAIN_API="https://pi.ruv.io"
|
|
BRAIN_API_KEY="${BRAIN_API_KEY:-ruvector-discovery-trainer-benevolent}"
|
|
RATE_LIMIT_SECONDS=1
|
|
|
|
# Counters
|
|
TOTAL=0
|
|
SUCCESS=0
|
|
FAIL=0
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
CYAN='\033[0;36m'
|
|
NC='\033[0m' # No Color
|
|
|
|
log_info() { echo -e "${CYAN}[INFO]${NC} $(date '+%H:%M:%S') $*"; }
|
|
log_ok() { echo -e "${GREEN}[OK]${NC} $(date '+%H:%M:%S') $*"; }
|
|
log_fail() { echo -e "${RED}[FAIL]${NC} $(date '+%H:%M:%S') $*"; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $(date '+%H:%M:%S') $*"; }
|
|
|
|
# -------------------------------------------------------------------
|
|
# Dependency check
|
|
# -------------------------------------------------------------------
|
|
check_deps() {
|
|
if ! command -v curl &>/dev/null; then
|
|
echo "curl is required but not installed. Aborting." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v jq &>/dev/null; then
|
|
log_warn "jq not found -- attempting to install..."
|
|
if command -v apt-get &>/dev/null; then
|
|
sudo apt-get update -qq && sudo apt-get install -y -qq jq
|
|
elif command -v yum &>/dev/null; then
|
|
sudo yum install -y jq
|
|
elif command -v brew &>/dev/null; then
|
|
brew install jq
|
|
else
|
|
echo "Cannot install jq automatically. Please install it manually." >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
log_info "Dependencies satisfied (curl, jq)"
|
|
}
|
|
|
|
# -------------------------------------------------------------------
|
|
# Obtain a fresh challenge nonce from the brain API
|
|
# -------------------------------------------------------------------
|
|
get_nonce() {
|
|
local response
|
|
response=$(curl -sf --max-time 10 "${BRAIN_API}/v1/challenge" 2>/dev/null) || {
|
|
log_fail "Failed to fetch challenge nonce from ${BRAIN_API}/v1/challenge"
|
|
return 1
|
|
}
|
|
|
|
local nonce
|
|
nonce=$(echo "$response" | jq -r '.nonce // empty')
|
|
if [[ -z "$nonce" ]]; then
|
|
log_fail "Challenge response did not contain a nonce"
|
|
return 1
|
|
fi
|
|
|
|
echo "$nonce"
|
|
}
|
|
|
|
# -------------------------------------------------------------------
|
|
# Post a single discovery to the brain API
|
|
# -------------------------------------------------------------------
|
|
post_memory() {
|
|
local title="$1"
|
|
local content="$2"
|
|
local tags_json="$3"
|
|
|
|
# Get a fresh nonce for each request
|
|
local nonce
|
|
nonce=$(get_nonce) || return 1
|
|
|
|
local payload
|
|
payload=$(jq -n \
|
|
--arg title "$title" \
|
|
--arg content "$content" \
|
|
--argjson tags "$tags_json" \
|
|
'{
|
|
title: $title,
|
|
content: $content,
|
|
category: "pattern",
|
|
tags: $tags
|
|
}')
|
|
|
|
local http_code
|
|
http_code=$(curl -s -o /dev/null -w "%{http_code}" \
|
|
--max-time 15 \
|
|
-X POST "${BRAIN_API}/v1/memories" \
|
|
-H "Content-Type: application/json" \
|
|
-H "Authorization: Bearer ${BRAIN_API_KEY}" \
|
|
-H "X-Challenge-Nonce: ${nonce}" \
|
|
-d "$payload" 2>/dev/null) || {
|
|
log_fail "curl error posting memory: ${title}"
|
|
return 1
|
|
}
|
|
|
|
if [[ "$http_code" =~ ^2 ]]; then
|
|
return 0
|
|
else
|
|
log_fail "HTTP ${http_code} for memory: ${title}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# -------------------------------------------------------------------
|
|
# Process a single discovery JSON file
|
|
# -------------------------------------------------------------------
|
|
process_file() {
|
|
local filepath="$1"
|
|
local filename
|
|
filename=$(basename "$filepath")
|
|
|
|
log_info "Processing file: ${filename}"
|
|
|
|
# Validate JSON
|
|
if ! jq empty "$filepath" 2>/dev/null; then
|
|
log_fail "Invalid JSON in ${filename} -- skipping"
|
|
return
|
|
fi
|
|
|
|
# Determine structure: could be an array of discoveries or an
|
|
# object with a "discoveries" key containing an array.
|
|
local entries_json
|
|
if jq -e 'type == "array"' "$filepath" &>/dev/null; then
|
|
entries_json=$(jq -c '.[]' "$filepath")
|
|
elif jq -e '.discoveries | type == "array"' "$filepath" &>/dev/null; then
|
|
entries_json=$(jq -c '.discoveries[]' "$filepath")
|
|
elif jq -e '.entries | type == "array"' "$filepath" &>/dev/null; then
|
|
entries_json=$(jq -c '.entries[]' "$filepath")
|
|
else
|
|
# Treat the whole file as a single discovery object
|
|
entries_json=$(jq -c '.' "$filepath")
|
|
fi
|
|
|
|
if [[ -z "$entries_json" ]]; then
|
|
log_warn "No discovery entries found in ${filename}"
|
|
return
|
|
fi
|
|
|
|
while IFS= read -r entry; do
|
|
TOTAL=$((TOTAL + 1))
|
|
|
|
# Extract title -- try common field names
|
|
local title
|
|
title=$(echo "$entry" | jq -r '
|
|
.title //
|
|
.name //
|
|
.discovery //
|
|
.summary //
|
|
("Discovery #" + (input_line_number | tostring))
|
|
' 2>/dev/null)
|
|
[[ -z "$title" || "$title" == "null" ]] && title="Discovery ${TOTAL}"
|
|
|
|
# Extract content -- try common field names
|
|
local content
|
|
content=$(echo "$entry" | jq -r '
|
|
.content //
|
|
.description //
|
|
.details //
|
|
.finding //
|
|
.text //
|
|
(. | tostring)
|
|
' 2>/dev/null)
|
|
[[ -z "$content" || "$content" == "null" ]] && content=$(echo "$entry" | jq -c '.')
|
|
|
|
# Extract tags -- merge with defaults
|
|
local file_tags
|
|
file_tags=$(echo "$entry" | jq -c '
|
|
(if .tags then
|
|
if (.tags | type) == "array" then .tags else [.tags] end
|
|
else
|
|
[]
|
|
end) + ["discovery"]
|
|
| unique
|
|
' 2>/dev/null)
|
|
[[ -z "$file_tags" || "$file_tags" == "null" ]] && file_tags='["discovery"]'
|
|
|
|
# Post to brain API
|
|
if post_memory "$title" "$content" "$file_tags"; then
|
|
SUCCESS=$((SUCCESS + 1))
|
|
log_ok "[${TOTAL}] ${title}"
|
|
else
|
|
FAIL=$((FAIL + 1))
|
|
log_fail "[${TOTAL}] ${title}"
|
|
fi
|
|
|
|
# Rate limiting
|
|
sleep "$RATE_LIMIT_SECONDS"
|
|
|
|
done <<< "$entries_json"
|
|
}
|
|
|
|
# -------------------------------------------------------------------
|
|
# Main
|
|
# -------------------------------------------------------------------
|
|
main() {
|
|
echo ""
|
|
echo "=========================================="
|
|
echo " Brain Training - Discovery Upload"
|
|
echo "=========================================="
|
|
echo ""
|
|
|
|
check_deps
|
|
|
|
# Verify discoveries directory
|
|
if [[ ! -d "$DISCOVERIES_DIR" ]]; then
|
|
log_fail "Discoveries directory not found: ${DISCOVERIES_DIR}"
|
|
exit 1
|
|
fi
|
|
|
|
# Collect discovery files
|
|
shopt -s nullglob
|
|
local files=("${DISCOVERIES_DIR}"/*_discoveries.json)
|
|
shopt -u nullglob
|
|
|
|
if [[ ${#files[@]} -eq 0 ]]; then
|
|
log_warn "No *_discoveries.json files found in ${DISCOVERIES_DIR}"
|
|
log_info "Discovery agents may not have completed yet."
|
|
exit 0
|
|
fi
|
|
|
|
log_info "Found ${#files[@]} discovery file(s) in ${DISCOVERIES_DIR}"
|
|
echo ""
|
|
|
|
# Process each file
|
|
for filepath in "${files[@]}"; do
|
|
process_file "$filepath"
|
|
echo ""
|
|
done
|
|
|
|
# Summary
|
|
echo "=========================================="
|
|
echo " Training Summary"
|
|
echo "=========================================="
|
|
echo ""
|
|
log_info "Total discoveries processed: ${TOTAL}"
|
|
log_ok "Successful submissions: ${SUCCESS}"
|
|
if [[ $FAIL -gt 0 ]]; then
|
|
log_fail "Failed submissions: ${FAIL}"
|
|
else
|
|
log_info "Failed submissions: 0"
|
|
fi
|
|
echo ""
|
|
|
|
if [[ $FAIL -gt 0 ]]; then
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
main "$@"
|