Initial commit: OpenClaw ops workspace

This commit is contained in:
2026-03-28 00:15:47 +00:00
commit f1aeaeefb5
42 changed files with 4297 additions and 0 deletions

View File

@@ -0,0 +1,166 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
usage() {
cat <<'EOF'
Usage:
switch-models.sh --non-main-primary <catalog-id> --non-main-fallbacks <m1,m2,...> [--clear-session-pins] [--pattern <old-model-pattern>]
Example:
switch-models.sh \
--non-main-primary "nanogpt/zai-org/glm-5" \
--non-main-fallbacks "lightning_ai/lightning-ai/kimi-k2.5,nanogpt/zai-org/glm-4.7" \
--clear-session-pins \
--pattern "gemini-3-flash"
Notes:
- Updates agents.list[].model for home/security/research.
- Keeps main/default model untouched.
- Validates candidates against live /v1/models.
- Optionally removes matching per-session model pins.
EOF
}
PRIMARY=""
FALLBACKS=""
CLEAR_PINS=0
PATTERN="gemini-3-flash"
while [[ $# -gt 0 ]]; do
case "$1" in
--non-main-primary)
PRIMARY="${2:-}"
shift 2
;;
--non-main-fallbacks)
FALLBACKS="${2:-}"
shift 2
;;
--clear-session-pins)
CLEAR_PINS=1
shift
;;
--pattern)
PATTERN="${2:-}"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown arg: $1" >&2
usage >&2
exit 1
;;
esac
done
if [[ -z "$PRIMARY" || -z "$FALLBACKS" ]]; then
echo "ERROR: --non-main-primary and --non-main-fallbacks are required" >&2
exit 1
fi
IFS=',' read -ra FB <<< "$FALLBACKS"
if [[ ${#FB[@]} -lt 1 ]]; then
echo "ERROR: at least 1 fallback required" >&2
exit 1
fi
for m in "$PRIMARY" "${FB[@]}"; do
m_clean="$(echo "${m#llm-proxy/}" | xargs)"
"$SCRIPT_DIR/validate-model.sh" "$m_clean" >/dev/null
echo "validated-live: $m_clean"
done
STATE_FILE="${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/openclaw.json"
if [[ ! -f "$STATE_FILE" ]]; then
for alt in \
"${OPENCLAW_STATE_DIR:-$HOME/.openclaw/state}/openclaw.json" \
"${OPENCLAW_CONFIG_DIR:-$HOME/.openclaw/config}/openclaw.json" \
"/opt/openclaw/state/openclaw.json"; do
if [[ -f "$alt" ]]; then
STATE_FILE="$alt"
break
fi
done
fi
[[ -f "$STATE_FILE" ]] || { echo "ERROR: openclaw.json not found" >&2; exit 1; }
# Validate against local configured catalog too (gateway uses this on restart)
node - <<'NODE' "$STATE_FILE" "$PRIMARY" "$FALLBACKS"
const fs=require('fs');
const p=process.argv[2];
const primary=process.argv[3].replace(/^llm-proxy\//,'');
const fallbacks=process.argv[4].split(',').map(s=>s.trim().replace(/^llm-proxy\//,'')).filter(Boolean);
const j=JSON.parse(fs.readFileSync(p,'utf8'));
const catalog=new Set((j.models?.providers?.['llm-proxy']?.models||[]).map(m=>m.id));
const missing=[];
if(!catalog.has(primary)) missing.push(primary);
for (const f of fallbacks) if(!catalog.has(f)) missing.push(f);
if (missing.length) {
console.error('ERROR: target models missing from local llm-proxy catalog in openclaw.json');
for (const m of [...new Set(missing)]) console.error(' - '+m);
process.exit(2);
}
console.log('validated-local-catalog: ok');
NODE
primary_full="llm-proxy/${PRIMARY#llm-proxy/}"
raw_fb="${FALLBACKS}"
fb_json="$(node - <<'NODE' "$PRIMARY" "$raw_fb"
const primary=process.argv[2].replace(/^llm-proxy\//,'');
const raw=process.argv[3].split(',').map(s=>s.trim().replace(/^llm-proxy\//,'')).filter(Boolean);
const seen=new Set();
const out=[];
for (const item of raw) {
if (item===primary) continue;
if (seen.has(item)) continue;
seen.add(item);
out.push(`llm-proxy/${item}`);
}
process.stdout.write(JSON.stringify(out));
NODE
)"
for aid in home security research; do
cmd1="openclaw config set agents.list[\"$aid\"].model.primary $primary_full"
echo "$cmd1"
eval "$cmd1"
cmd2="openclaw config set agents.list[\"$aid\"].model.fallbacks '$fb_json' --json"
echo "$cmd2"
eval "$cmd2"
done
if [[ "$CLEAR_PINS" -eq 1 ]]; then
echo "clearing matching session model pins pattern=$PATTERN"
for aid in home security research; do
sess="/home/node/.openclaw/agents/${aid}/sessions/sessions.json"
[[ -f "$sess" ]] || continue
node - <<'NODE' "$sess" "$PATTERN" "$aid"
const fs=require('fs');
const file=process.argv[2];
const pattern=new RegExp(process.argv[3],'i');
const aid=process.argv[4];
const j=JSON.parse(fs.readFileSync(file,'utf8'));
let removed=0;
for (const [k,v] of Object.entries(j)) {
const model=(v&&v.model)?String(v.model):'';
if (model && pattern.test(model)) {
delete v.model;
removed++;
}
}
fs.writeFileSync(file, JSON.stringify(j,null,2)+'\n');
console.log(`agent=${aid} removed_model_pins=${removed}`);
NODE
done
fi
echo "running post-change audit..."
"$SCRIPT_DIR/audit-model-state.sh" "$PATTERN"
echo "done. restart gateway to apply runtime changes."