chore: import upstream snapshot with attribution
pi-agent-plugin checks / lint (push) Has been cancelled
pi-agent-plugin checks / test (20) (push) Has been cancelled
pi-agent-plugin checks / test (22) (push) Has been cancelled
pi-agent-plugin checks / build (push) Has been cancelled
TypeScript SDK CI / check_changes (push) Has been cancelled
TypeScript SDK CI / changelog_check (push) Has been cancelled
ci / changelog_check (push) Has been cancelled
ci / check_changes (push) Has been cancelled
ci / build_mem0 (3.10) (push) Has been cancelled
ci / build_mem0 (3.11) (push) Has been cancelled
ci / build_mem0 (3.12) (push) Has been cancelled
CLI Node CI / lint (push) Has been cancelled
CLI Node CI / test (20) (push) Has been cancelled
CLI Node CI / test (22) (push) Has been cancelled
CLI Node CI / build (push) Has been cancelled
CLI Python CI / lint (push) Has been cancelled
CLI Python CI / test (3.10) (push) Has been cancelled
CLI Python CI / test (3.11) (push) Has been cancelled
CLI Python CI / test (3.12) (push) Has been cancelled
CLI Python CI / build (push) Has been cancelled
openclaw checks / lint (push) Has been cancelled
openclaw checks / test (20) (push) Has been cancelled
openclaw checks / test (22) (push) Has been cancelled
openclaw checks / build (push) Has been cancelled
opencode-plugin checks / build (push) Has been cancelled
TypeScript SDK CI / build_ts_sdk (20) (push) Has been cancelled
TypeScript SDK CI / build_ts_sdk (22) (push) Has been cancelled
TypeScript SDK CI / integration_ts_sdk (20) (push) Has been cancelled
TypeScript SDK CI / integration_ts_sdk (22) (push) Has been cancelled
pi-agent-plugin checks / lint (push) Has been cancelled
pi-agent-plugin checks / test (20) (push) Has been cancelled
pi-agent-plugin checks / test (22) (push) Has been cancelled
pi-agent-plugin checks / build (push) Has been cancelled
TypeScript SDK CI / check_changes (push) Has been cancelled
TypeScript SDK CI / changelog_check (push) Has been cancelled
ci / changelog_check (push) Has been cancelled
ci / check_changes (push) Has been cancelled
ci / build_mem0 (3.10) (push) Has been cancelled
ci / build_mem0 (3.11) (push) Has been cancelled
ci / build_mem0 (3.12) (push) Has been cancelled
CLI Node CI / lint (push) Has been cancelled
CLI Node CI / test (20) (push) Has been cancelled
CLI Node CI / test (22) (push) Has been cancelled
CLI Node CI / build (push) Has been cancelled
CLI Python CI / lint (push) Has been cancelled
CLI Python CI / test (3.10) (push) Has been cancelled
CLI Python CI / test (3.11) (push) Has been cancelled
CLI Python CI / test (3.12) (push) Has been cancelled
CLI Python CI / build (push) Has been cancelled
openclaw checks / lint (push) Has been cancelled
openclaw checks / test (20) (push) Has been cancelled
openclaw checks / test (22) (push) Has been cancelled
openclaw checks / build (push) Has been cancelled
opencode-plugin checks / build (push) Has been cancelled
TypeScript SDK CI / build_ts_sdk (20) (push) Has been cancelled
TypeScript SDK CI / build_ts_sdk (22) (push) Has been cancelled
TypeScript SDK CI / integration_ts_sdk (20) (push) Has been cancelled
TypeScript SDK CI / integration_ts_sdk (22) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
"""Delete request_logs rows older than REQUEST_LOG_RETENTION_DAYS (default 30).
|
||||
|
||||
Run inside the `mem0` container, or wire into cron / a systemd timer on the host.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
from sqlalchemy import delete
|
||||
|
||||
from db import SessionLocal
|
||||
from models import RequestLog
|
||||
|
||||
|
||||
def main() -> int:
|
||||
raw = os.environ.get("REQUEST_LOG_RETENTION_DAYS", "").strip() or "30"
|
||||
try:
|
||||
retention_days = int(raw)
|
||||
except ValueError:
|
||||
sys.stderr.write("REQUEST_LOG_RETENTION_DAYS must be an integer.\n")
|
||||
return 1
|
||||
if retention_days < 1:
|
||||
sys.stderr.write("REQUEST_LOG_RETENTION_DAYS must be >= 1.\n")
|
||||
return 1
|
||||
|
||||
cutoff = datetime.now(timezone.utc) - timedelta(days=retention_days)
|
||||
with SessionLocal() as session:
|
||||
result = session.execute(delete(RequestLog).where(RequestLog.created_at < cutoff))
|
||||
session.commit()
|
||||
sys.stdout.write(f"Deleted {result.rowcount or 0} request_logs rows older than {cutoff.isoformat()}.\n")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,41 @@
|
||||
"""Reset a user's password by email. Run inside the `mem0` container."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from sqlalchemy import select
|
||||
|
||||
from auth import hash_password
|
||||
from db import SessionLocal
|
||||
from models import User
|
||||
|
||||
MIN_PASSWORD_LENGTH = 8
|
||||
|
||||
|
||||
def main() -> int:
|
||||
email = os.environ.get("EMAIL", "").strip()
|
||||
password = os.environ.get("PASSWORD", "")
|
||||
|
||||
if not email or not password:
|
||||
print("error: EMAIL and PASSWORD environment variables are required.", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
if len(password) < MIN_PASSWORD_LENGTH:
|
||||
print(f"error: password must be at least {MIN_PASSWORD_LENGTH} characters.", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
with SessionLocal() as db:
|
||||
user = db.scalar(select(User).where(User.email == email))
|
||||
if user is None:
|
||||
print(f"error: no user found with email {email}.", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
user.password_hash = hash_password(password)
|
||||
db.commit()
|
||||
|
||||
print(f"Password reset for {email}.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Executable
+86
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
API_URL="${API_URL:-http://localhost:8888}"
|
||||
DASHBOARD_URL="${DASHBOARD_URL:-http://localhost:3000}"
|
||||
EMAIL="${EMAIL:-admin@mem0.dev}"
|
||||
PASSWORD="${PASSWORD:-$(python3 -c 'import secrets; print(secrets.token_urlsafe(16))')}"
|
||||
NAME="${NAME:-Admin}"
|
||||
OUTPUT="${OUTPUT:-text}"
|
||||
|
||||
echo "=== Mem0 Self-Hosted Seed ==="
|
||||
echo "API: $API_URL"
|
||||
echo ""
|
||||
|
||||
# Check if setup is needed
|
||||
SETUP=$(curl -s "$API_URL/auth/setup-status")
|
||||
NEEDS_SETUP=$(echo "$SETUP" | python3 -c "import sys,json; print(json.load(sys.stdin).get('needsSetup', True))" 2>/dev/null || echo "True")
|
||||
|
||||
if [ "$NEEDS_SETUP" = "True" ]; then
|
||||
echo "Creating admin account..."
|
||||
REGISTER_PAYLOAD=$(NAME="$NAME" EMAIL="$EMAIL" PASSWORD="$PASSWORD" python3 -c 'import json, os; print(json.dumps({"name": os.environ["NAME"], "email": os.environ["EMAIL"], "password": os.environ["PASSWORD"]}))')
|
||||
REGISTER=$(curl -s -X POST "$API_URL/auth/register" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$REGISTER_PAYLOAD")
|
||||
echo "$REGISTER" | python3 -c "import sys,json; d=json.load(sys.stdin); print(' Admin created.' if 'access_token' in d else f' Error: {d}')" 2>/dev/null
|
||||
else
|
||||
echo "Admin already exists, logging in..."
|
||||
fi
|
||||
|
||||
# Login
|
||||
echo "Logging in..."
|
||||
LOGIN_PAYLOAD=$(EMAIL="$EMAIL" PASSWORD="$PASSWORD" python3 -c 'import json, os; print(json.dumps({"email": os.environ["EMAIL"], "password": os.environ["PASSWORD"]}))')
|
||||
LOGIN=$(curl -s -X POST "$API_URL/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$LOGIN_PAYLOAD")
|
||||
TOKEN=$(echo "$LOGIN" | python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])" 2>/dev/null)
|
||||
|
||||
if [ -z "$TOKEN" ]; then
|
||||
echo " Login failed: $LOGIN"
|
||||
echo " Admin exists but PASSWORD didn't match. Recover with:"
|
||||
echo " make clean && make bootstrap (wipes data)"
|
||||
echo " make reset-admin-password EMAIL=<email> PASSWORD=<pass> (keeps data)"
|
||||
exit 1
|
||||
fi
|
||||
echo " Logged in."
|
||||
|
||||
# Create API key
|
||||
echo "Creating API key..."
|
||||
KEY_RESP=$(curl -s -X POST "$API_URL/api-keys" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-d '{"label": "dev-seed-key"}')
|
||||
API_KEY=$(echo "$KEY_RESP" | python3 -c "import sys,json; print(json.load(sys.stdin)['key'])" 2>/dev/null)
|
||||
|
||||
if [ -z "$API_KEY" ]; then
|
||||
echo " API key creation failed: $KEY_RESP"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$OUTPUT" = "json" ]; then
|
||||
DASHBOARD_URL="$DASHBOARD_URL" API_URL="$API_URL" EMAIL="$EMAIL" PASSWORD="$PASSWORD" API_KEY="$API_KEY" python3 -c 'import json, os; print(json.dumps({"dashboard_url": os.environ["DASHBOARD_URL"], "api_url": os.environ["API_URL"], "email": os.environ["EMAIL"], "password": os.environ["PASSWORD"], "api_key": os.environ["API_KEY"]}))'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "=== Ready ==="
|
||||
echo "Email: $EMAIL"
|
||||
echo "Password: $PASSWORD"
|
||||
echo "API Key: $API_KEY"
|
||||
echo ""
|
||||
echo "Open your dashboard at $DASHBOARD_URL to see and manage your memories in your browser."
|
||||
echo ""
|
||||
|
||||
if ! grep -qE '^(OPENAI|ANTHROPIC|GOOGLE)_API_KEY=.' .env 2>/dev/null; then
|
||||
echo "!! No LLM provider API key set in server/.env."
|
||||
echo " Set OPENAI_API_KEY (or ANTHROPIC_API_KEY / GOOGLE_API_KEY), then:"
|
||||
echo " docker compose up -d --force-recreate mem0"
|
||||
echo " The curl below will return provider_auth_failed until you do."
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "Test it:"
|
||||
echo " curl -X POST $API_URL/memories \\"
|
||||
echo " -H 'X-API-Key: $API_KEY' \\"
|
||||
echo " -H 'Content-Type: application/json' \\"
|
||||
echo " -d '{\"messages\": [{\"role\": \"user\", \"content\": \"I like hiking\"}], \"user_id\": \"seed-\$(date +%s)\"}'"
|
||||
Reference in New Issue
Block a user