From e0cfec16664e97abdab2ca58f5dbbb08ba960410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Thu, 4 Dec 2025 13:16:42 +0100 Subject: [PATCH] cli installation --- docker/README.md | 155 ------ docker/standalone/docker-compose.yml | 25 - docker/start.sh | 41 -- hindsight-api/hindsight_api/api/__init__.py | 4 +- hindsight-cli/install.sh | 12 +- hindsight-control-plane/package-lock.json | 502 +++++++++++++++++- hindsight-control-plane/package.json | 3 +- .../src/app/banks/[bankId]/page.tsx | 16 +- .../src/components/bank-profile-view.tsx | 498 +++++++++++------ .../src/components/sidebar.tsx | 7 +- .../src/components/stats-view.tsx | 234 -------- hindsight-docs/docs/api-reference/mcp.md | 191 +++---- hindsight-docs/docs/sdks/mcp.md | 100 ++-- hindsight-docs/src/css/custom.css | 24 +- uv.lock | 6 +- 15 files changed, 970 insertions(+), 848 deletions(-) delete mode 100644 docker/README.md delete mode 100644 docker/standalone/docker-compose.yml delete mode 100755 docker/start.sh delete mode 100644 hindsight-control-plane/src/components/stats-view.tsx diff --git a/docker/README.md b/docker/README.md deleted file mode 100644 index 16126f3f..00000000 --- a/docker/README.md +++ /dev/null @@ -1,155 +0,0 @@ -# Hindsight Docker - -Run Hindsight with Docker in standalone or distributed mode. - -## Quick Start (Standalone) - -```bash -cd docker -./start.sh -``` - -**Force rebuild after code changes:** -```bash -./start.sh --build # Quick: rebuild and start -# or -./rebuild.sh # Complete: rebuild from scratch (no cache) -``` - -Access: -- **Control Plane**: http://localhost:3000 -- **API**: http://localhost:8888 - -Press `Ctrl+C` to stop. - -## What You Get - -**Standalone** (default, simple): -- One container with API + Control Plane + embedded database -- Perfect for local development and simple deployments - -**Distributed** (advanced): -- Separate containers for API and Control Plane -- Better for production, scaling, or custom configurations - -## Deployment Modes - -### 1. Standalone (Recommended) - -All-in-one container with embedded pg0 database. - -```bash -./start.sh -# or -cd standalone -docker-compose up -``` - -**Data storage:** `/app/data` volume - -### 2. Distributed (Advanced) - -Separate API and Control Plane containers. - -```bash -cd services -docker-compose up -``` - -**Data storage:** `api_data` volume - -See `services/README.md` for details. - -## Data Management - -**Reset data:** -```bash -# Standalone -cd standalone && docker-compose down -v - -# Distributed -cd services && docker-compose down -v -``` - -## Building Images - -```bash -# Standalone -cd standalone -docker build -f Dockerfile -t hindsight:latest ../.. - -# Services -cd services -./build-all.sh -``` - -## Using External Database - -Both modes use embedded pg0 by default. To use external PostgreSQL: - -```bash -export HINDSIGHT_API_DATABASE_URL=postgresql://user:pass@host:5432/db -``` - -## Directory Structure - -``` -docker/ -├── start.sh # Quick start (standalone) -├── README.md # This file -├── standalone/ # All-in-one deployment -│ ├── Dockerfile -│ ├── docker-compose.yml -│ └── start-all.sh -└── services/ # Distributed deployment - ├── docker-compose.yml - ├── api.Dockerfile - ├── control-plane.Dockerfile - ├── build-all.sh - └── README.md -``` - -## Advanced Usage - -**Background mode:** -```bash -cd standalone -docker-compose up -d -docker-compose logs -f -docker-compose down -``` - -**Custom configuration:** -Edit `standalone/docker-compose.yml` or `services/docker-compose.yml` - -## Environment Variables - -Hindsight requires configuration through environment variables (all prefixed with `HINDSIGHT_`). - -### Required: -- `HINDSIGHT_API_LLM_API_KEY` - Your LLM API key (OpenAI, Anthropic, etc.) - -### Optional: -- `HINDSIGHT_API_LLM_MODEL` - Model name (default: gpt-4o-mini) -- `HINDSIGHT_API_LLM_BASE_URL` - API base URL (default: https://api.openai.com/v1) -- `HINDSIGHT_API_LOG_LEVEL` - Logging level: debug, info, warning, error -- `HINDSIGHT_API_DATABASE_URL` - External PostgreSQL connection (uses embedded pg0 by default) - -### Setup Options: - -**Option 1: .env file (recommended)** -```bash -# Copy example file -cp .env.example .env - -# Edit .env and add your API key -HINDSIGHT_API_LLM_API_KEY=sk-... -``` - -**Option 2: Export in shell** -```bash -export HINDSIGHT_API_LLM_API_KEY=sk-... -export HINDSIGHT_API_LLM_MODEL=gpt-4o-mini -``` - -The `start.sh` script automatically loads `.env` if it exists and validates the API key is set. diff --git a/docker/standalone/docker-compose.yml b/docker/standalone/docker-compose.yml deleted file mode 100644 index 02e5c5fd..00000000 --- a/docker/standalone/docker-compose.yml +++ /dev/null @@ -1,25 +0,0 @@ -services: - hindsight: - image: hindsight - build: - context: ../.. - dockerfile: docker/standalone/Dockerfile - env_file: - - ../../.env - ports: - - "9999:9999" - - "8888:8888" - environment: - # These override env_file values only when set in host shell - # Default values are applied only when not set in env_file or host - HINDSIGHT_API_HOST: ${HINDSIGHT_API_HOST:-0.0.0.0} - HINDSIGHT_API_PORT: ${HINDSIGHT_API_PORT:-8888} - HINDSIGHT_API_LOG_LEVEL: ${HINDSIGHT_API_LOG_LEVEL:-info} - # HINDSIGHT_API_DATABASE_URL can be set if you want to use an external database - # If not set, embedded pg0 will be used automatically - volumes: - - hindsight_data:/home/hindsight/.pg0 - restart: unless-stopped - -volumes: - hindsight_data: diff --git a/docker/start.sh b/docker/start.sh deleted file mode 100755 index f4e0d8c7..00000000 --- a/docker/start.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -# Start Hindsight (standalone all-in-one) - -cd "$(dirname "$0")" - -# Check for --build flag -BUILD_FLAG="" -if [[ "$1" == "--build" ]] || [[ "$1" == "-b" ]]; then - BUILD_FLAG="--build" - echo "🔨 Forcing rebuild of images..." - echo "" -fi - -echo "🚀 Starting Hindsight..." -echo "" - -# Load .env file from project root if it exists -if [ -f ../.env ]; then - echo "📝 Loading environment variables from .env file..." - export $(grep -v '^#' ../.env | grep -v '^$' | xargs) -fi - -# Check for required HINDSIGHT_API_LLM_API_KEY -if [ -z "$HINDSIGHT_API_LLM_API_KEY" ]; then - echo "⚠️ Warning: HINDSIGHT_API_LLM_API_KEY is not set" - echo "" - echo "Set it by either:" - echo " 1. Creating a .env file in the project root with: HINDSIGHT_API_LLM_API_KEY=your-key" - echo " 2. Exporting: export HINDSIGHT_API_LLM_API_KEY=your-key" - echo "" - read -p "Continue anyway? (y/N) " -n 1 -r - echo - if [[ ! $REPLY =~ ^[Yy]$ ]]; then - exit 1 - fi -fi - -cd standalone - -# Run docker-compose with optional --build flag -docker-compose up $BUILD_FLAG diff --git a/hindsight-api/hindsight_api/api/__init__.py b/hindsight-api/hindsight_api/api/__init__.py index 0172ab7c..d35c311a 100644 --- a/hindsight-api/hindsight_api/api/__init__.py +++ b/hindsight-api/hindsight_api/api/__init__.py @@ -67,8 +67,8 @@ def create_app( # Create MCP server with shared memory instance mcp_server = create_mcp_server(memory=memory) - # Mount at specified path using http_app (modern non-SSE alternative) - app.mount(mcp_mount_path, mcp_server.http_app()) + # Mount at specified path using sse_app for compatibility with mcp-remote + app.mount(mcp_mount_path, mcp_server.sse_app()) logger.info(f"MCP server enabled at {mcp_mount_path}") except ImportError as e: logger.error(f"MCP server requested but dependencies not available: {e}") diff --git a/hindsight-cli/install.sh b/hindsight-cli/install.sh index 9fa4ae4c..1c653c87 100755 --- a/hindsight-cli/install.sh +++ b/hindsight-cli/install.sh @@ -4,7 +4,7 @@ set -e # Hindsight CLI installer # Usage: curl -sSf https://your-domain.com/install.sh | sh -REPO_URL="https://github.com/your-org/hindsight-cli" +REPO_URL="https://github.com/vectorize-io/hindsight" INSTALL_DIR="${HINDSIGHT_INSTALL_DIR:-$HOME/.local/bin}" BINARY_NAME="hindsight" @@ -47,9 +47,9 @@ detect_platform() { case "$os" in Darwin) if [[ "$arch" == "arm64" ]] || [[ "$arch" == "aarch64" ]]; then - echo "macos-arm64" + echo "darwin-arm64" elif [[ "$arch" == "x86_64" ]]; then - echo "macos-x86_64" + echo "darwin-amd64" else print_error "Unsupported macOS architecture: $arch" exit 1 @@ -57,7 +57,7 @@ detect_platform() { ;; Linux) if [[ "$arch" == "x86_64" ]]; then - echo "linux-x86_64" + echo "linux-amd64" elif [[ "$arch" == "aarch64" ]] || [[ "$arch" == "arm64" ]]; then echo "linux-arm64" else @@ -78,14 +78,14 @@ download_binary() { local download_url="${REPO_URL}/releases/latest/download/hindsight-${platform}" local tmp_file="/tmp/hindsight-$$" - print_info "Downloading Hindsight CLI for $platform..." + print_info "Downloading Hindsight CLI for $platform..." >&2 if command -v curl > /dev/null 2>&1; then curl -fsSL "$download_url" -o "$tmp_file" elif command -v wget > /dev/null 2>&1; then wget -q "$download_url" -O "$tmp_file" else - print_error "Neither curl nor wget found. Please install one of them." + print_error "Neither curl nor wget found. Please install one of them." >&2 exit 1 fi diff --git a/hindsight-control-plane/package-lock.json b/hindsight-control-plane/package-lock.json index ad57fb2d..54244bd3 100644 --- a/hindsight-control-plane/package-lock.json +++ b/hindsight-control-plane/package-lock.json @@ -1,12 +1,12 @@ { "name": "hindsight-control-plane", - "version": "0.0.12", + "version": "0.0.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hindsight-control-plane", - "version": "0.0.12", + "version": "0.0.16", "license": "ISC", "dependencies": { "@radix-ui/react-checkbox": "^1.3.3", @@ -36,6 +36,7 @@ "react-cytoscape": "^1.0.6", "react-dom": "^19.2.0", "react18-json-view": "^0.2.9", + "recharts": "^3.5.1", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.17", "tailwindcss-animate": "^1.0.7", @@ -44,7 +45,7 @@ }, "../hindsight-clients/typescript": { "name": "@vectorize-io/hindsight-client", - "version": "0.0.12", + "version": "0.0.16", "license": "MIT", "devDependencies": { "@hey-api/openapi-ts": "^0.88.0", @@ -4309,6 +4310,111 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.1.tgz", + "integrity": "sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.1.tgz", + "integrity": "sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.1.tgz", + "integrity": "sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.1.tgz", + "integrity": "sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.1.tgz", + "integrity": "sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.1.tgz", + "integrity": "sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.1.tgz", + "integrity": "sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "license": "MIT", @@ -5089,10 +5195,58 @@ "version": "1.1.1", "license": "MIT" }, + "node_modules/@reduxjs/toolkit": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.11.0.tgz", + "integrity": "sha512-hBjYg0aaRL1O2Z0IqWhnTLytnjDIxekmRxm1snsHjHaKVmIF1HiImWqsq+PuEbn6zdMlkIj9WofK1vR8jjx+Xw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@standard-schema/utils": "^0.3.0", + "immer": "^11.0.0", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17.0.0 || ^18 || ^19", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@reduxjs/toolkit/node_modules/immer": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-11.0.1.tgz", + "integrity": "sha512-naDCyggtcBWANtIrjQEajhhBEuL9b0Zg4zmlWK2CzS6xCWSE39/vvf4LqnMjUAWHBhot4m9MHCM/Z+mfWhUkiA==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "license": "MIT" }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", + "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", + "license": "MIT" + }, + "node_modules/@standard-schema/utils": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz", + "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==", + "license": "MIT" + }, "node_modules/@swc/helpers": { "version": "0.5.15", "license": "Apache-2.0", @@ -5159,6 +5313,69 @@ "tailwindcss": "4.1.17" } }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "license": "MIT" @@ -5196,6 +5413,12 @@ "version": "4.2.5", "license": "MIT" }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.6.tgz", + "integrity": "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==", + "license": "MIT" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.46.3", "license": "MIT", @@ -6010,6 +6233,27 @@ "cytoscape": "^3.2.22" } }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/d3-dispatch": { "version": "1.0.6", "license": "BSD-3-Clause" @@ -6022,10 +6266,56 @@ "d3-selection": "1" } }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-path": { "version": "1.0.9", "license": "BSD-3-Clause" }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-selection": { "version": "1.4.2", "license": "BSD-3-Clause" @@ -6037,6 +6327,30 @@ "d3-path": "1" } }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/d3-timer": { "version": "1.0.10", "license": "BSD-3-Clause" @@ -6117,6 +6431,12 @@ } } }, + "node_modules/decimal.js-light": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/decimal.js-light/-/decimal.js-light-2.5.1.tgz", + "integrity": "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "license": "MIT" @@ -6356,6 +6676,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-toolkit": { + "version": "1.42.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.42.0.tgz", + "integrity": "sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==", + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/escalade": { "version": "3.2.0", "license": "MIT", @@ -6748,6 +7078,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "license": "MIT" @@ -7140,6 +7476,16 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "license": "MIT", @@ -7173,6 +7519,15 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/is-array-buffer": { "version": "3.0.5", "license": "MIT", @@ -8206,6 +8561,29 @@ "version": "16.13.1", "license": "MIT" }, + "node_modules/react-redux": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz", + "integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==", + "license": "MIT", + "dependencies": { + "@types/use-sync-external-store": "^0.0.6", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "@types/react": "^18.2.25 || ^19", + "react": "^18.0 || ^19", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, "node_modules/react-remove-scroll": { "version": "2.7.2", "license": "MIT", @@ -8279,6 +8657,51 @@ "react": ">=16.8.0" } }, + "node_modules/recharts": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/recharts/-/recharts-3.5.1.tgz", + "integrity": "sha512-+v+HJojK7gnEgG6h+b2u7k8HH7FhyFUzAc4+cPrsjL4Otdgqr/ecXzAnHciqlzV1ko064eNcsdzrYOM78kankA==", + "license": "MIT", + "workspaces": [ + "www" + ], + "dependencies": { + "@reduxjs/toolkit": "1.x.x || 2.x.x", + "clsx": "^2.1.1", + "decimal.js-light": "^2.5.1", + "es-toolkit": "^1.39.3", + "eventemitter3": "^5.0.1", + "immer": "^10.1.1", + "react-redux": "8.x.x || 9.x.x", + "reselect": "5.1.1", + "tiny-invariant": "^1.3.3", + "use-sync-external-store": "^1.2.2", + "victory-vendor": "^37.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-is": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "license": "MIT", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", "license": "MIT", @@ -8317,6 +8740,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==", + "license": "MIT" + }, "node_modules/resolve": { "version": "1.22.11", "license": "MIT", @@ -8871,6 +9300,12 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", + "license": "MIT" + }, "node_modules/tinyglobby": { "version": "0.2.15", "license": "MIT", @@ -9202,6 +9637,67 @@ } } }, + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/victory-vendor": { + "version": "37.3.6", + "resolved": "https://registry.npmjs.org/victory-vendor/-/victory-vendor-37.3.6.tgz", + "integrity": "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==", + "license": "MIT AND ISC", + "dependencies": { + "@types/d3-array": "^3.0.3", + "@types/d3-ease": "^3.0.0", + "@types/d3-interpolate": "^3.0.1", + "@types/d3-scale": "^4.0.2", + "@types/d3-shape": "^3.1.0", + "@types/d3-time": "^3.0.0", + "@types/d3-timer": "^3.0.0", + "d3-array": "^3.1.6", + "d3-ease": "^3.0.1", + "d3-interpolate": "^3.0.1", + "d3-scale": "^4.0.2", + "d3-shape": "^3.1.0", + "d3-time": "^3.0.0", + "d3-timer": "^3.0.1" + } + }, + "node_modules/victory-vendor/node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/victory-vendor/node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/victory-vendor/node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/webcola": { "version": "3.4.0", "license": "MIT", diff --git a/hindsight-control-plane/package.json b/hindsight-control-plane/package.json index 937f1d2a..72efc24c 100644 --- a/hindsight-control-plane/package.json +++ b/hindsight-control-plane/package.json @@ -13,7 +13,6 @@ "license": "ISC", "description": "Control plane for Hindsight - Semantic memory system", "dependencies": { - "@vectorize-io/hindsight-client": "file:../hindsight-clients/typescript", "@radix-ui/react-checkbox": "^1.3.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-label": "^2.1.8", @@ -25,6 +24,7 @@ "@types/node": "^24.10.0", "@types/react": "^19.2.2", "@types/react-dom": "^19.2.2", + "@vectorize-io/hindsight-client": "file:../hindsight-clients/typescript", "autoprefixer": "^10.4.21", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -40,6 +40,7 @@ "react-cytoscape": "^1.0.6", "react-dom": "^19.2.0", "react18-json-view": "^0.2.9", + "recharts": "^3.5.1", "tailwind-merge": "^3.4.0", "tailwindcss": "^4.1.17", "tailwindcss-animate": "^1.0.7", diff --git a/hindsight-control-plane/src/app/banks/[bankId]/page.tsx b/hindsight-control-plane/src/app/banks/[bankId]/page.tsx index 6366b1a4..96e33949 100644 --- a/hindsight-control-plane/src/app/banks/[bankId]/page.tsx +++ b/hindsight-control-plane/src/app/banks/[bankId]/page.tsx @@ -9,11 +9,10 @@ import { DocumentsView } from '@/components/documents-view'; import { EntitiesView } from '@/components/entities-view'; import { ThinkView } from '@/components/think-view'; import { SearchDebugView } from '@/components/search-debug-view'; -import { StatsView } from '@/components/stats-view'; import { BankProfileView } from '@/components/bank-profile-view'; import { useBank } from '@/lib/bank-context'; -type NavItem = 'recall' | 'reflect' | 'data' | 'documents' | 'entities' | 'profile' | 'stats'; +type NavItem = 'recall' | 'reflect' | 'data' | 'documents' | 'entities' | 'profile'; type DataSubTab = 'world' | 'bank' | 'opinion'; export default function BankPage() { @@ -23,7 +22,7 @@ export default function BankPage() { const { currentBank, setCurrentBank } = useBank(); const bankId = params.bankId as string; - const view = (searchParams.get('view') || 'data') as NavItem; + const view = (searchParams.get('view') || 'profile') as NavItem; const subTab = (searchParams.get('subTab') || 'world') as DataSubTab; // Sync URL bank with context @@ -164,17 +163,6 @@ export default function BankPage() { )} - - {/* Stats Tab (Stats & Operations) */} - {view === 'stats' && ( -
-

Statistics & Operations

-

- View detailed statistics and async operations for this memory bank. -

- -
- )} diff --git a/hindsight-control-plane/src/components/bank-profile-view.tsx b/hindsight-control-plane/src/components/bank-profile-view.tsx index df9b61f7..0dbb10a9 100644 --- a/hindsight-control-plane/src/components/bank-profile-view.tsx +++ b/hindsight-control-plane/src/components/bank-profile-view.tsx @@ -7,7 +7,9 @@ import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Textarea } from '@/components/ui/textarea'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { RefreshCw, Save, User, Brain, FileText, Clock } from 'lucide-react'; +import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; +import { RefreshCw, Save, User, Brain, FileText, Clock, AlertCircle, CheckCircle, Database, Link2, FolderOpen, Activity } from 'lucide-react'; +import { RadarChart, PolarGrid, PolarAngleAxis, PolarRadiusAxis, Radar, ResponsiveContainer, Tooltip } from 'recharts'; interface PersonalityTraits { openness: number; @@ -44,81 +46,155 @@ interface BankStats { failed_operations: number; } -const TRAIT_LABELS: Record = { +interface Operation { + id: string; + task_type: string; + items_count: number; + document_id?: string; + created_at: string; + status: string; + error_message?: string; +} + +const TRAIT_LABELS: Record = { openness: { label: 'Openness', + shortLabel: 'O', description: 'Openness to experience - curiosity, creativity, and willingness to try new things', lowLabel: 'Practical', highLabel: 'Creative' }, conscientiousness: { label: 'Conscientiousness', + shortLabel: 'C', description: 'Organization, dependability, and self-discipline', lowLabel: 'Flexible', highLabel: 'Organized' }, extraversion: { label: 'Extraversion', + shortLabel: 'E', description: 'Sociability, assertiveness, and positive emotions', lowLabel: 'Reserved', highLabel: 'Outgoing' }, agreeableness: { label: 'Agreeableness', + shortLabel: 'A', description: 'Cooperation, trust, and altruism', lowLabel: 'Skeptical', highLabel: 'Trusting' }, neuroticism: { label: 'Neuroticism', + shortLabel: 'N', description: 'Emotional instability and tendency toward negative emotions', lowLabel: 'Calm', highLabel: 'Sensitive' }, bias_strength: { - label: 'Personality Influence', + label: 'Influence', + shortLabel: 'I', description: 'How strongly personality traits influence opinions and responses', lowLabel: 'Neutral', highLabel: 'Strong' } }; -function PersonalitySlider({ - trait, - value, - onChange, - disabled -}: { - trait: keyof PersonalityTraits; - value: number; - onChange: (value: number) => void; - disabled?: boolean; +function PersonalityRadarChart({ personality, editMode, editPersonality, onEditChange }: { + personality: PersonalityTraits; + editMode: boolean; + editPersonality: PersonalityTraits; + onEditChange: (trait: keyof PersonalityTraits, value: number) => void; }) { - const info = TRAIT_LABELS[trait]; - const percentage = Math.round(value * 100); + const data = editMode ? editPersonality : personality; + + const chartData = [ + { trait: 'Openness', value: Math.round(data.openness * 100), fullMark: 100 }, + { trait: 'Conscientiousness', value: Math.round(data.conscientiousness * 100), fullMark: 100 }, + { trait: 'Extraversion', value: Math.round(data.extraversion * 100), fullMark: 100 }, + { trait: 'Agreeableness', value: Math.round(data.agreeableness * 100), fullMark: 100 }, + { trait: 'Neuroticism', value: Math.round(data.neuroticism * 100), fullMark: 100 }, + ]; return ( -
-
- - {percentage}% +
+
+ + + + + + + [`${value}%`, 'Score']} + /> + +
-
- onChange(parseInt(e.target.value) / 100)} - disabled={disabled} - className="w-full h-2 bg-muted rounded-lg appearance-none cursor-pointer accent-primary disabled:opacity-50 disabled:cursor-not-allowed" - /> -
- {info.lowLabel} - {info.highLabel} + + {editMode && ( +
+ {(Object.keys(TRAIT_LABELS) as Array).filter(t => t !== 'bias_strength').map((trait) => ( +
+
+ + {Math.round(editPersonality[trait] * 100)}% +
+ onEditChange(trait, parseInt(e.target.value) / 100)} + className="w-full h-1.5 bg-muted rounded-lg appearance-none cursor-pointer accent-primary" + /> +
+ ))}
+ )} + + {/* Influence Strength - always shown */} +
+
+
+ +

How strongly traits affect responses

+
+ {Math.round(data.bias_strength * 100)}% +
+ {editMode && ( + onEditChange('bias_strength', parseInt(e.target.value) / 100)} + className="w-full h-2 bg-muted rounded-lg appearance-none cursor-pointer accent-primary" + /> + )}
-

{info.description}

); } @@ -127,6 +203,7 @@ export function BankProfileView() { const { currentBank } = useBank(); const [profile, setProfile] = useState(null); const [stats, setStats] = useState(null); + const [operations, setOperations] = useState([]); const [loading, setLoading] = useState(false); const [saving, setSaving] = useState(false); const [editMode, setEditMode] = useState(false); @@ -148,12 +225,14 @@ export function BankProfileView() { setLoading(true); try { - const [profileData, statsData] = await Promise.all([ + const [profileData, statsData, opsData] = await Promise.all([ client.getBankProfile(currentBank), - client.getBankStats(currentBank) + client.getBankStats(currentBank), + client.listOperations(currentBank) ]); setProfile(profileData); setStats(statsData as BankStats); + setOperations((opsData as any)?.operations || []); // Initialize edit state setEditName(profileData.name); @@ -199,6 +278,9 @@ export function BankProfileView() { useEffect(() => { if (currentBank) { loadData(); + // Refresh operations every 5 seconds + const interval = setInterval(loadData, 5000); + return () => clearInterval(interval); } }, [currentBank]); @@ -230,22 +312,15 @@ export function BankProfileView() {

{profile?.name || currentBank}

-

Bank ID: {currentBank}

+

{currentBank}

{editMode ? ( <> - - - @@ -280,133 +348,245 @@ export function BankProfileView() {
- {/* Stats Overview */} + {/* Stats Overview - Compact cards */} {stats && ( - - - - - Memory Overview - - Summary of stored memories and connections - - -
-
-
Total Memories
-
{stats.total_nodes}
+
+ + +
+
+ +
+
+

Memories

+

{stats.total_nodes}

+
-
-
Total Links
-
{stats.total_links}
-
-
-
Documents
-
{stats.total_documents}
-
-
-
Pending Ops
-
{stats.pending_operations}
-
-
+ + - {/* Memory Type Breakdown */} -
-
-
World Facts
-
{stats.nodes_by_fact_type?.world || 0}
+ + +
+
+ +
+
+

Links

+

{stats.total_links}

+
-
-
Bank Facts
-
{stats.nodes_by_fact_type?.bank || 0}
+ + + + + +
+
+ +
+
+

Documents

+

{stats.total_documents}

+
-
-
Opinions
-
{stats.nodes_by_fact_type?.opinion || 0}
+ + + + 0 ? 'from-amber-500/10 to-amber-600/5 border-amber-500/20' : 'from-slate-500/10 to-slate-600/5 border-slate-500/20'}`}> + +
+
0 ? 'bg-amber-500/20' : 'bg-slate-500/20'}`}> + 0 ? 'text-amber-500 animate-pulse' : 'text-slate-500'}`} /> +
+
+

Pending

+

{stats.pending_operations}

+
-
-
-
+ + +
+ )} + + {/* Memory Type Breakdown */} + {stats && ( +
+
+

World Facts

+

{stats.nodes_by_fact_type?.world || 0}

+
+
+

Bank Facts

+

{stats.nodes_by_fact_type?.bank || 0}

+
+
+

Opinions

+

{stats.nodes_by_fact_type?.opinion || 0}

+
+
)}
- {/* Basic Info */} + {/* Personality Chart */} - - - - Basic Information + + + + Personality Profile - Name and identity for this memory bank - - -
- - {editMode ? ( - setEditName(e.target.value)} - placeholder="Enter a name for this bank" - className="mt-1" - /> - ) : ( -

{profile?.name || 'Unnamed'}

- )} -
-
-
- - {/* Background */} - - - - - Background - - Context and background information for this memory bank + Big Five personality traits that influence responses - {editMode ? ( -