diff --git a/infrastructure/08-memorybank-setup.sh b/infrastructure/08-memorybank-setup.sh index 861c050..d584415 100644 --- a/infrastructure/08-memorybank-setup.sh +++ b/infrastructure/08-memorybank-setup.sh @@ -1,5 +1,6 @@ #!/usr/bin/env bash # 08-memorybank-setup.sh — Create Vertex AI Agent Engine (Memory Bank) instance +# Uses REST API directly — no SDK version dependency # Idempotent — safe to run multiple times # Source .env before running: source .env @@ -10,10 +11,12 @@ set -euo pipefail : "${AGENT_SA:?Set AGENT_SA}" MEMORY_INSTANCE_DISPLAY_NAME="${MEMORY_INSTANCE_DISPLAY_NAME:-${PROJECT_ID}-memory-bank}" +# Agent Engine lives in the same region as REGION (us-central1 is fine, eu also works) +MEMORY_REGION="${MEMORY_REGION:-${REGION}}" echo "=== 08: Setting up Vertex AI Memory Bank (Agent Engine) ===" echo " Project : ${PROJECT_ID}" -echo " Region : ${REGION}" +echo " Region : ${MEMORY_REGION}" echo " Instance : ${MEMORY_INSTANCE_DISPLAY_NAME}" echo "" @@ -23,77 +26,96 @@ gcloud services enable aiplatform.googleapis.com \ --project="${PROJECT_ID}" --quiet echo "✓ APIs enabled" -# ── Ensure correct SDK version is installed ──────────────────────────────── -echo " Ensuring google-cloud-aiplatform>=1.111.0 ..." -pip install --quiet --user "google-cloud-aiplatform>=1.111.0" 2>&1 | tail -2 +# ── REST: token + endpoint ──────────────────────────────────────────────────── +TOKEN=$(gcloud auth print-access-token) +API="https://${MEMORY_REGION}-aiplatform.googleapis.com/v1beta1" +PARENT="projects/${PROJECT_ID}/locations/${MEMORY_REGION}" -# Use the user-local python so .local/lib packages are picked up -PYTHON="$(which python3)" -if python3 -c "import sys; sys.exit(0 if any('.local' in p for p in sys.path) else 1)" 2>/dev/null; then - PYTHON="python3" +# ── Check if instance exists ─────────────────────────────────────────────────── +echo " Checking for existing Agent Engine instance..." +EXISTING_LIST=$(curl -sf \ + -H "Authorization: Bearer ${TOKEN}" \ + "${API}/${PARENT}/reasoningEngines" 2>/dev/null || echo '{}') + +ENGINE_NAME=$(echo "${EXISTING_LIST}" | python3 -c " +import sys, json +data = json.load(sys.stdin) +for e in data.get('reasoningEngines', []): + if e.get('displayName') == '${MEMORY_INSTANCE_DISPLAY_NAME}': + print(e['name']) + break +" 2>/dev/null || true) + +if [[ -n "${ENGINE_NAME}" ]]; then + echo "✓ Memory Bank already exists: ${ENGINE_NAME}" else - # Force user site-packages - PYTHON="python3 -c 'import sys, site; sys.path.insert(0, site.getusersitepackages()); exec(open("/dev/stdin").read())'" + echo " Creating Agent Engine '${MEMORY_INSTANCE_DISPLAY_NAME}' in ${MEMORY_REGION}..." + + RESPONSE=$(curl -sf -X POST \ + -H "Authorization: Bearer ${TOKEN}" \ + -H "Content-Type: application/json" \ + "${API}/${PARENT}/reasoningEngines" \ + -d '{ + "displayName": "'"${MEMORY_INSTANCE_DISPLAY_NAME}"'", + "spec": {} + }' 2>/dev/null || echo '{}') + + OPERATION=$(echo "${RESPONSE}" | python3 -c " +import sys, json +d = json.load(sys.stdin) +print(d.get('name', '')) +" 2>/dev/null || true) + + if [[ -z "${OPERATION}" ]]; then + echo "ERROR: No operation returned. Response:" + echo "${RESPONSE}" + exit 1 + fi + + echo " Waiting for LRO: ${OPERATION}" + for i in $(seq 1 30); do + sleep 10 + LRO=$(curl -sf \ + -H "Authorization: Bearer ${TOKEN}" \ + "https://${MEMORY_REGION}-aiplatform.googleapis.com/v1beta1/${OPERATION}" 2>/dev/null || echo '{}') + DONE=$(echo "${LRO}" | python3 -c " +import sys, json +print(json.load(sys.stdin).get('done', False)) +" 2>/dev/null || echo 'False') + if [[ "${DONE}" == "True" ]]; then + # Re-list to get name reliably + ENGINE_NAME=$(curl -sf \ + -H "Authorization: Bearer ${TOKEN}" \ + "${API}/${PARENT}/reasoningEngines" 2>/dev/null \ + | python3 -c " +import sys, json +data = json.load(sys.stdin) +for e in data.get('reasoningEngines', []): + if e.get('displayName') == '${MEMORY_INSTANCE_DISPLAY_NAME}': + print(e['name']) + break +" 2>/dev/null || true) + echo "✓ Agent Engine created: ${ENGINE_NAME}" + break + fi + echo " ... still waiting (${i}/30)" + done + + if [[ -z "${ENGINE_NAME}" ]]; then + echo "ERROR: Agent Engine creation timed out or failed." + exit 1 + fi fi -# Simple check: can we import agent_engines? -if ! python3 -c "import sys, site; sys.path.insert(0, site.getusersitepackages()); from vertexai.preview import agent_engines" 2>/dev/null; then - echo "ERROR: agent_engines still not importable after install. Try:" - echo " pip install --upgrade google-cloud-aiplatform" - exit 1 -fi -echo "✓ Python SDK ready (agent_engines importable)" - -# ── Create or find Memory Bank instance ─────────────────────────────────── -python3 - << 'PYEOF' -import sys, site -sys.path.insert(0, site.getusersitepackages()) - -import os - -try: - import vertexai - from vertexai.preview import agent_engines -except ImportError as e: - print(f"ERROR: Failed to import agent_engines: {e}") - sys.exit(1) - -PROJECT_ID = os.environ["PROJECT_ID"] -REGION = os.environ["REGION"] -DISP_NAME = os.environ.get("MEMORY_INSTANCE_DISPLAY_NAME", f"{PROJECT_ID}-memory-bank") - -vertexai.init(project=PROJECT_ID, location=REGION) - -existing = None -try: - for eng in agent_engines.list(): - if hasattr(eng, "display_name") and eng.display_name == DISP_NAME: - existing = eng - print(f"✓ Memory Bank already exists: {eng.resource_name}") - break -except Exception as e: - print(f" WARNING: Could not list agent engines: {e}") - -if existing is None: - try: - instance = agent_engines.create(display_name=DISP_NAME) - print(f"✓ Memory Bank created: {instance.resource_name}") - existing = instance - except Exception as e: - print(f"ERROR: Failed to create Memory Bank: {e}") - sys.exit(1) - -if existing: - resource_name = existing.resource_name - with open("/tmp/memory_engine_name.txt", "w") as f: - f.write(resource_name) - print(f"") - print(f" Resource name : {resource_name}") - print(f"") - print(f" ACTION REQUIRED — add to .env:") - print(f' export MEMORY_ENGINE_NAME="{resource_name}"') -PYEOF +# ── Write output ────────────────────────────────────────────────────────────────── +echo "${ENGINE_NAME}" > /tmp/memory_engine_name.txt +echo "" +echo " Resource name : ${ENGINE_NAME}" +echo " Region : ${MEMORY_REGION}" +echo "" +echo " ACTION REQUIRED — add to .env:" +echo " export MEMORY_ENGINE_NAME=\"${ENGINE_NAME}\"" echo "" echo "=== 08: Memory Bank setup COMPLETE ===" echo " NEXT: copy MEMORY_ENGINE_NAME into .env, then run 05-cloudrun-deploy.sh"