{"repo": "aristoteleo/pantheonos", "files": {"docker/docker-entrypoint-dual-mode.sh": {"c15440df1633f50128fa78c8ac27dc848de6786a": {"t": 1785745942.3189397, "n": 16436, "h": "8a7cf51573c1b61d", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Structural \"default workspace\" layout — GATED during rollout via\n # PANTHEON_DEFAULT_WORKSPACE so a build is a no-op until the hub opts in.\n # When enabled: the Volume (/workspace) becomes the user's HOME so ~/.pantheon\n # (projects.json, .env, settings, oauth) persists, and the Volume root is a\n # CONTAINER for many independent workspaces (default = default_workspace).\n # Off = legacy layout (HOME=/root, single workspace at the Volume root).\n DW_ENABLED=\"${PANTHEON_DEFAULT_WORKSPACE:-false}\"\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n export HOME=/workspace\n # Caches must NOT land on the Volume (bloat) — redirect to ephemeral /root.\n export XDG_CACHE_HOME=/root/.cache\n export HF_HOME=/root/.cache/huggingface\n export HUGGINGFACE_HUB_CACHE=/root/.cache/huggingface\n export TORCH_HOME=/root/.cache/torch\n export PIP_CACHE_DIR=/root/.cache/pip\n export UV_CACHE_DIR=/root/.cache/uv\n export MPLCONFIGDIR=/root/.cache/matplotlib\n mkdir -p /root/.cache\n fi\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n DEFAULT_WS=/workspace/default_workspace\n\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n MIGRATION_MARKER=/workspace/.pantheon/.migrated_to_default_workspace_v2\n # One-time migration (v2). The OLD layout used the Volume ROOT itself as the\n # single workspace; the NEW layout makes the root a pure CONTAINER. Move the\n # ENTIRE root workspace into default_workspace — loose files AND existing\n # project dirs — so default_workspace holds all your prior work, and the\n # root has only default_workspace + the global .pantheon (+ future SIBLING\n # workspaces you create). v2 also corrects an earlier build that wrongly\n # left project dirs at the root as siblings; it is guarded only by the\n # marker (not by default_workspace existing) so it re-runs to fix a v1 layout.\n if [ ! -f \"$MIGRATION_MARKER\" ]; then\n echo \"Migrating Volume-root content into default_workspace (v2) ...\"\n mkdir -p \"$DEFAULT_WS\"\n moved=0\n for entry in /workspace/*; do # unquoted glob: matches NON-dotfiles only\n [ -e \"$entry\" ] || continue\n [ \"$(basename \"$entry\")\" = \"default_workspace\" ] && continue\n if mv \"$entry\" \"$DEFAULT_WS/\" 2>/dev/null; then moved=$((moved+1)); else echo \" (could not move $(basename \"$entry\"))\"; fi\n done\n # The old root .pantheon (chats/brain/memory) becomes the default\n # workspace's — unless it already has one (a prior v1 migration moved it).\n if [ -d /workspace/.pantheon ] && [ ! -d \"$DEFAULT_WS/.pantheon\" ]; then\n mv /workspace/.pantheon \"$DEFAULT_WS/.pantheon\" 2>/dev/null || echo \" (could not move root .pantheon)\"\n fi\n mkdir -p /workspace/.pantheon\n touch \"$MIGRATION_MARKER\"\n echo \"✓ Migration v2 complete ($moved item(s) now under default_workspace)\"\n fi\n mkdir -p /workspace/.pantheon \"$DEFAULT_WS/.pantheon\"\n echo \"✓ Global store /workspace/.pantheon + default workspace $DEFAULT_WS ready\"\n\n # Keep the GLOBAL factory cache fresh every boot: global mode materializes\n # factory into ~/.pantheon (=/workspace/.pantheon, now PERSISTENT), so stale\n # copies would shadow an image upgrade's new templates. User data\n # (projects.json, settings, .env, oauth) is untouched.\n echo \"Refreshing global factory template cache...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Factory cache cleared (re-materializes on startup)\"\n else\n # Legacy layout: single workspace at the Volume root, ephemeral HOME.\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Pantheon-Fleet: when this sandbox is wired to a fleet, join it as a Node in\n # the background so the agent can transfer files to/from it over the data plane\n # via a single transfer() interface (dst_node=\"local\" resolves to this node).\n if [ -n \"${FLEET_CONTROLLER_URL:-}\" ] && command -v fleet >/dev/null 2>&1; then\n echo \"[fleet] joining fleet as node sandbox-${ID_HASH} ...\"\n mkdir -p /tmp/fleet-node\n fleet up --controller \"${FLEET_CONTROLLER_URL}\" --key \"${FLEET_KEY}\" \\\n --name \"sandbox-${ID_HASH}\" --state-dir /tmp/fleet-node \\\n > /tmp/fleet-node.log 2>&1 &\n fi\n\n # Run the endpoint IN the default workspace so work_dir (=cwd at import) makes\n # default_workspace the active project, while HOME=/workspace keeps ~/.pantheon\n # (global store) at the Volume root. Users create sibling workspaces under\n # /workspace and switch to them from the UI. (Legacy layout stays in /workspace.)\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n cd \"$DEFAULT_WS\" || cd /workspace\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "a41b541e419e24f4a4fe959ba3bf6eb4cef4d629": {"t": 1785758124.2419155, "n": 16436, "h": "8a7cf51573c1b61d", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Structural \"default workspace\" layout — GATED during rollout via\n # PANTHEON_DEFAULT_WORKSPACE so a build is a no-op until the hub opts in.\n # When enabled: the Volume (/workspace) becomes the user's HOME so ~/.pantheon\n # (projects.json, .env, settings, oauth) persists, and the Volume root is a\n # CONTAINER for many independent workspaces (default = default_workspace).\n # Off = legacy layout (HOME=/root, single workspace at the Volume root).\n DW_ENABLED=\"${PANTHEON_DEFAULT_WORKSPACE:-false}\"\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n export HOME=/workspace\n # Caches must NOT land on the Volume (bloat) — redirect to ephemeral /root.\n export XDG_CACHE_HOME=/root/.cache\n export HF_HOME=/root/.cache/huggingface\n export HUGGINGFACE_HUB_CACHE=/root/.cache/huggingface\n export TORCH_HOME=/root/.cache/torch\n export PIP_CACHE_DIR=/root/.cache/pip\n export UV_CACHE_DIR=/root/.cache/uv\n export MPLCONFIGDIR=/root/.cache/matplotlib\n mkdir -p /root/.cache\n fi\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n DEFAULT_WS=/workspace/default_workspace\n\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n MIGRATION_MARKER=/workspace/.pantheon/.migrated_to_default_workspace_v2\n # One-time migration (v2). The OLD layout used the Volume ROOT itself as the\n # single workspace; the NEW layout makes the root a pure CONTAINER. Move the\n # ENTIRE root workspace into default_workspace — loose files AND existing\n # project dirs — so default_workspace holds all your prior work, and the\n # root has only default_workspace + the global .pantheon (+ future SIBLING\n # workspaces you create). v2 also corrects an earlier build that wrongly\n # left project dirs at the root as siblings; it is guarded only by the\n # marker (not by default_workspace existing) so it re-runs to fix a v1 layout.\n if [ ! -f \"$MIGRATION_MARKER\" ]; then\n echo \"Migrating Volume-root content into default_workspace (v2) ...\"\n mkdir -p \"$DEFAULT_WS\"\n moved=0\n for entry in /workspace/*; do # unquoted glob: matches NON-dotfiles only\n [ -e \"$entry\" ] || continue\n [ \"$(basename \"$entry\")\" = \"default_workspace\" ] && continue\n if mv \"$entry\" \"$DEFAULT_WS/\" 2>/dev/null; then moved=$((moved+1)); else echo \" (could not move $(basename \"$entry\"))\"; fi\n done\n # The old root .pantheon (chats/brain/memory) becomes the default\n # workspace's — unless it already has one (a prior v1 migration moved it).\n if [ -d /workspace/.pantheon ] && [ ! -d \"$DEFAULT_WS/.pantheon\" ]; then\n mv /workspace/.pantheon \"$DEFAULT_WS/.pantheon\" 2>/dev/null || echo \" (could not move root .pantheon)\"\n fi\n mkdir -p /workspace/.pantheon\n touch \"$MIGRATION_MARKER\"\n echo \"✓ Migration v2 complete ($moved item(s) now under default_workspace)\"\n fi\n mkdir -p /workspace/.pantheon \"$DEFAULT_WS/.pantheon\"\n echo \"✓ Global store /workspace/.pantheon + default workspace $DEFAULT_WS ready\"\n\n # Keep the GLOBAL factory cache fresh every boot: global mode materializes\n # factory into ~/.pantheon (=/workspace/.pantheon, now PERSISTENT), so stale\n # copies would shadow an image upgrade's new templates. User data\n # (projects.json, settings, .env, oauth) is untouched.\n echo \"Refreshing global factory template cache...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Factory cache cleared (re-materializes on startup)\"\n else\n # Legacy layout: single workspace at the Volume root, ephemeral HOME.\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Pantheon-Fleet: when this sandbox is wired to a fleet, join it as a Node in\n # the background so the agent can transfer files to/from it over the data plane\n # via a single transfer() interface (dst_node=\"local\" resolves to this node).\n if [ -n \"${FLEET_CONTROLLER_URL:-}\" ] && command -v fleet >/dev/null 2>&1; then\n echo \"[fleet] joining fleet as node sandbox-${ID_HASH} ...\"\n mkdir -p /tmp/fleet-node\n fleet up --controller \"${FLEET_CONTROLLER_URL}\" --key \"${FLEET_KEY}\" \\\n --name \"sandbox-${ID_HASH}\" --state-dir /tmp/fleet-node \\\n > /tmp/fleet-node.log 2>&1 &\n fi\n\n # Run the endpoint IN the default workspace so work_dir (=cwd at import) makes\n # default_workspace the active project, while HOME=/workspace keeps ~/.pantheon\n # (global store) at the Volume root. Users create sibling workspaces under\n # /workspace and switch to them from the UI. (Legacy layout stays in /workspace.)\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n cd \"$DEFAULT_WS\" || cd /workspace\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "fe05718c2c91e99360df189ae913e95bb2ed9016": {"t": 1785758126.5888376, "n": 16367, "h": "5cdd46066a8b9966", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Structural \"default workspace\" layout — GATED during rollout via\n # PANTHEON_DEFAULT_WORKSPACE so a build is a no-op until the hub opts in.\n # When enabled: the Volume (/workspace) becomes the user's HOME so ~/.pantheon\n # (projects.json, .env, settings, oauth) persists, and the Volume root is a\n # CONTAINER for many independent workspaces (default = default_workspace).\n # Off = legacy layout (HOME=/root, single workspace at the Volume root).\n DW_ENABLED=\"${PANTHEON_DEFAULT_WORKSPACE:-false}\"\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n export HOME=/workspace\n # Caches must NOT land on the Volume (bloat) — redirect to ephemeral /root.\n export XDG_CACHE_HOME=/root/.cache\n export HF_HOME=/root/.cache/huggingface\n export HUGGINGFACE_HUB_CACHE=/root/.cache/huggingface\n export TORCH_HOME=/root/.cache/torch\n export PIP_CACHE_DIR=/root/.cache/pip\n export UV_CACHE_DIR=/root/.cache/uv\n export MPLCONFIGDIR=/root/.cache/matplotlib\n mkdir -p /root/.cache\n fi\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n DEFAULT_WS=/workspace/default_workspace\n\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n MIGRATION_MARKER=/workspace/.pantheon/.migrated_to_default_workspace\n # One-time migration. The OLD layout used the Volume ROOT itself as the\n # single workspace; the NEW layout makes the root a container so users can\n # create many independent workspaces. Relocate the root's own workspace\n # into default_workspace, preserving everything:\n # - loose files / non-project dirs -> default_workspace/\n # - dirs that are their OWN workspace (have a .pantheon) -> stay as siblings\n # - the root's .pantheon (chats/brain/memory/settings) -> default_workspace/.pantheon\n # A fresh /workspace/.pantheon is then the GLOBAL store (~/.pantheon).\n if [ ! -f \"$MIGRATION_MARKER\" ] && [ ! -d \"$DEFAULT_WS\" ]; then\n echo \"Migrating Volume-root workspace into default_workspace ...\"\n mkdir -p \"$DEFAULT_WS\"\n moved=0\n for entry in /workspace/*; do # unquoted glob: matches NON-dotfiles only\n [ -e \"$entry\" ] || continue\n base=$(basename \"$entry\")\n [ \"$base\" = \"default_workspace\" ] && continue\n if [ -d \"$entry\" ] && [ -d \"$entry/.pantheon\" ]; then continue; fi # independent workspace\n if mv \"$entry\" \"$DEFAULT_WS/\" 2>/dev/null; then moved=$((moved+1)); else echo \" (could not move $base)\"; fi\n done\n if [ -d /workspace/.pantheon ]; then\n mv /workspace/.pantheon \"$DEFAULT_WS/.pantheon\" 2>/dev/null || echo \" (could not move root .pantheon)\"\n fi\n mkdir -p /workspace/.pantheon\n touch \"$MIGRATION_MARKER\"\n echo \"✓ Migration complete ($moved loose item(s) moved; root .pantheon -> default_workspace)\"\n fi\n mkdir -p /workspace/.pantheon \"$DEFAULT_WS/.pantheon\"\n echo \"✓ Global store /workspace/.pantheon + default workspace $DEFAULT_WS ready\"\n\n # Keep the GLOBAL factory cache fresh every boot: global mode materializes\n # factory into ~/.pantheon (=/workspace/.pantheon, now PERSISTENT), so stale\n # copies would shadow an image upgrade's new templates. User data\n # (projects.json, settings, .env, oauth) is untouched.\n echo \"Refreshing global factory template cache...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Factory cache cleared (re-materializes on startup)\"\n else\n # Legacy layout: single workspace at the Volume root, ephemeral HOME.\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Pantheon-Fleet: when this sandbox is wired to a fleet, join it as a Node in\n # the background so the agent can transfer files to/from it over the data plane\n # via a single transfer() interface (dst_node=\"local\" resolves to this node).\n if [ -n \"${FLEET_CONTROLLER_URL:-}\" ] && command -v fleet >/dev/null 2>&1; then\n echo \"[fleet] joining fleet as node sandbox-${ID_HASH} ...\"\n mkdir -p /tmp/fleet-node\n fleet up --controller \"${FLEET_CONTROLLER_URL}\" --key \"${FLEET_KEY}\" \\\n --name \"sandbox-${ID_HASH}\" --state-dir /tmp/fleet-node \\\n > /tmp/fleet-node.log 2>&1 &\n fi\n\n # Run the endpoint IN the default workspace so work_dir (=cwd at import) makes\n # default_workspace the active project, while HOME=/workspace keeps ~/.pantheon\n # (global store) at the Volume root. Users create sibling workspaces under\n # /workspace and switch to them from the UI. (Legacy layout stays in /workspace.)\n if [ \"$DW_ENABLED\" = \"true\" ]; then\n cd \"$DEFAULT_WS\" || cd /workspace\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "8f1bf359e1dc53a01435d75d872f9d35fc811725": {"t": 1785758128.760131, "n": 12371, "h": "8a85600d1edfeae6", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n # Initialize workspace structure\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n\n # Clear stale project-level templates before forcing an explicit factory\n # materialization. Normal startup uses runtime factory fallback and does not\n # copy factory templates.\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Pantheon-Fleet: when this sandbox is wired to a fleet, join it as a Node in\n # the background so the agent can transfer files to/from it over the data plane\n # via a single transfer() interface (dst_node=\"local\" resolves to this node).\n if [ -n \"${FLEET_CONTROLLER_URL:-}\" ] && command -v fleet >/dev/null 2>&1; then\n echo \"[fleet] joining fleet as node sandbox-${ID_HASH} ...\"\n mkdir -p /tmp/fleet-node\n fleet up --controller \"${FLEET_CONTROLLER_URL}\" --key \"${FLEET_KEY}\" \\\n --name \"sandbox-${ID_HASH}\" --state-dir /tmp/fleet-node \\\n > /tmp/fleet-node.log 2>&1 &\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "54cd8b46d98007bd85008dff52595c04c082ac05": {"t": 1785758130.0089295, "n": 11740, "h": "6b2fcfb1f5a4d6e6", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n # Initialize workspace structure\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n\n # Clear stale project-level templates before forcing an explicit factory\n # materialization. Normal startup uses runtime factory fallback and does not\n # copy factory templates.\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "98ee366c42b2a645423373a08eaa989c9747f2aa": {"t": 1785758131.5872262, "n": 11677, "h": "c21e0484a3384a4f", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n # Initialize workspace structure\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n\n # Clear stale project-level templates before forcing a factory sync with the\n # current PANTHEON_TEMPLATE_SYNC_SCOPE.\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "eaf60e3f961675e4e6632b953084f0bb3ca57159": {"t": 1785758133.2875814, "n": 11625, "h": "e5533902ca1218cf", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n # Initialize workspace structure\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n\n # Clear stale project-level templates from pre-project-system images\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "ce3ae92f937d7dc3b33919498d9797be7549180c": {"t": 1785758134.9672577, "n": 11674, "h": "04324f365af35f0b", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" QDRANT_LOCATION: ${QDRANT_LOCATION}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n # Initialize workspace structure\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n\n # Clear stale project-level templates from pre-project-system images\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n echo \"Clearing stale project-level templates...\"\n rm -rf /workspace/.pantheon/agents /workspace/.pantheon/teams /workspace/.pantheon/prompts /workspace/.pantheon/skills /workspace/.pantheon/.factory_hashes.json\n echo \"✓ Stale templates cleared\"\n fi\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Build sync-templates flag\n SYNC_FLAG=\"\"\n if [ \"${PANTHEON_RESET_TEMPLATES}\" = \"true\" ]; then\n SYNC_FLAG=\"--sync-templates\"\n fi\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG}\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" ${SYNC_FLAG} \"$@\"\n fi\nfi\n"}, "31b0e864990bf569459589be6d30079ab9b92da0": {"t": 1785758137.0238523, "n": 11094, "h": "79fbc53b8ae832d1", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" QDRANT_LOCATION: ${QDRANT_LOCATION}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 0.2; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n # Initialize workspace structure\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\"\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" \"$@\"\n fi\nfi\n"}, "e298e73ef878ba06676f391aadf0aa920c82b982": {"t": 1785758139.4076326, "n": 11583, "h": "161d691418139f44", "c": "#!/bin/bash\nset -e\n\necho \"=========================================\"\necho \"Pantheon Docker Container\"\necho \"Mode: ${PANTHEON_MODE:-hub}\"\necho \"=========================================\"\n\n# ========== MODE DETECTION ==========\nif [ \"${PANTHEON_MODE}\" = \"standalone\" ]; then\n echo \"[STANDALONE MODE] Starting with auto-start-nats and auto-ui\"\n\n # Standalone mode: for end users, starts NATS internally\n WORKSPACE=${WORKSPACE:-/workspace}\n FRONTEND_URL=${FRONTEND_URL:-https://pantheon-ui.aristoteleo.com}\n\n echo \"Configuration:\"\n echo \" Workspace: ${WORKSPACE}\"\n echo \" Frontend URL: ${FRONTEND_URL}\"\n echo \"\"\n\n # Initialize workspace\n mkdir -p \"${WORKSPACE}/.pantheon\"\n\n # Create .env template if not exists\n if [ ! -f \"${WORKSPACE}/.env\" ]; then\n cat > \"${WORKSPACE}/.env.example\" << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, restart the container to apply changes.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, restart the container to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n cp \"${WORKSPACE}/.env.example\" \"${WORKSPACE}/.env\"\n echo \"✓ Created .env template at ${WORKSPACE}/.env\"\n echo \" → Edit ${WORKSPACE}/.env to configure your API keys\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n # Detect external port mapping (from environment variable or default 8080)\n # Users can specify via -e NATS_EXTERNAL_PORT=9000\n NATS_EXTERNAL_PORT=\"${NATS_EXTERNAL_PORT:-8080}\"\n\n # Skip interactive configuration wizard (auto-skip in Docker environment)\n # Users should provide API keys via environment variables\n export SKIP_SETUP_WIZARD=1\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon UI (Standalone Mode)\"\n echo \"=========================================\"\n echo \"\"\n echo \"📡 NATS WebSocket will be available at:\"\n echo \" ws://localhost:${NATS_EXTERNAL_PORT} (from host machine)\"\n echo \" ws://:${NATS_EXTERNAL_PORT} (from external network)\"\n echo \"\"\n echo \"⏳ Starting services... (this may take a few seconds)\"\n echo \"\"\n\n # Create temporary log file for URL capture\n LOG_FILE=\"/tmp/pantheon-startup.log\"\n\n # Start command: use pantheon ui instead of pantheon.chatroom\n # Run in background with tee to display logs and capture to file\n python -m pantheon ui \\\n --workspace_path=\"${WORKSPACE}\" \\\n --auto-start-nats \\\n --auto-ui=\"${FRONTEND_URL}\" \\\n \"$@\" 2>&1 | tee \"${LOG_FILE}\" &\n\n PANTHEON_PID=$!\n\n # Wait for service startup and capture connection URL\n echo \"Waiting for connection URL...\"\n MAX_WAIT=60 # Maximum wait time: 60 seconds\n WAIT_COUNT=0\n CONNECTION_URL=\"\"\n\n while [ $WAIT_COUNT -lt $MAX_WAIT ]; do\n # Check if process is still running\n if ! kill -0 $PANTHEON_PID 2>/dev/null; then\n echo \"\"\n echo \"❌ ERROR: Pantheon process exited unexpectedly\"\n echo \"Check logs above for error details\"\n exit 1\n fi\n\n # Try to extract connection URL from logs\n if [ -f \"${LOG_FILE}\" ]; then\n # Find lines containing full connection URL (with #/?nats=)\n CONNECTION_URL=$(grep -oP 'https?://[^/]+/.*#/\\?nats=ws://[^&]+&service=[^&]+&auto=true' \"${LOG_FILE}\" | tail -1)\n\n if [ -n \"$CONNECTION_URL\" ]; then\n # Replace port in URL with user-specified external port\n # Replace ws://localhost:8080 or ws://0.0.0.0:8080 with user-specified port\n CONNECTION_URL=$(echo \"$CONNECTION_URL\" | sed \"s|ws://[^:]*:8080|ws://localhost:${NATS_EXTERNAL_PORT}|g\")\n\n # URL found, display prominent message\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 🎉 Pantheon UI Ready! ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"📋 Connection Information:\"\n echo \"\"\n\n # Extract components\n NATS_WS=$(echo \"$CONNECTION_URL\" | grep -oP 'nats=\\K[^&]+')\n SERVICE_ID=$(echo \"$CONNECTION_URL\" | grep -oP 'service=\\K[^&]+')\n\n echo \" 🌐 Frontend URL:\"\n echo \" ${FRONTEND_URL}\"\n echo \"\"\n echo \" 📡 NATS WebSocket:\"\n echo \" ${NATS_WS}\"\n echo \"\"\n echo \" 🔑 Service ID:\"\n echo \" ${SERVICE_ID}\"\n echo \"\"\n echo \" 🔗 Full Connection URL (click to open):\"\n echo \" ${CONNECTION_URL}\"\n echo \"\"\n echo \"╔════════════════════════════════════════════════════════════════╗\"\n echo \"║ 👉 Copy the URL above and paste it in your browser ║\"\n echo \"╚════════════════════════════════════════════════════════════════╝\"\n echo \"\"\n echo \"💡 Tips:\"\n echo \" - To access from another device, replace 'localhost' with your machine's IP\"\n echo \" - NATS monitoring dashboard: http://localhost:8222\"\n echo \" - Press Ctrl+C to stop the container\"\n echo \"\"\n\n break\n fi\n fi\n\n sleep 1\n WAIT_COUNT=$((WAIT_COUNT + 1))\n\n # Show progress every 10 seconds\n if [ $((WAIT_COUNT % 10)) -eq 0 ]; then\n echo \"Still waiting for services to start... (${WAIT_COUNT}s)\"\n fi\n done\n\n if [ -z \"$CONNECTION_URL\" ]; then\n echo \"\"\n echo \"⚠️ WARNING: Could not detect connection URL automatically\"\n echo \" The service may still be starting. Check the logs above.\"\n echo \"\"\n fi\n\n # Wait for main process\n wait $PANTHEON_PID\n\nelse\n # ========== HUB MODE (original logic) ==========\n echo \"[HUB MODE] Starting as agent pod for Pantheon Hub\"\n\n # Default ID_HASH if not provided\n ID_HASH=${ID_HASH:-\"default\"}\n\n echo \"Environment:\"\n echo \" ID_HASH: ${ID_HASH}\"\n echo \" PANTHEON_REMOTE_BACKEND: ${PANTHEON_REMOTE_BACKEND}\"\n echo \" NATS_SERVERS: ${NATS_SERVERS}\"\n echo \" QDRANT_LOCATION: ${QDRANT_LOCATION}\"\n echo \" WORKSPACE: $(pwd)\"\n echo \"\"\n\n # Wait for NATS server (if NATS_MONITOR_URL is set)\n if [ -n \"$NATS_MONITOR_URL\" ]; then\n echo \"Waiting for NATS server at $NATS_MONITOR_URL...\"\n timeout 30 bash -c \"until curl -sf $NATS_MONITOR_URL/healthz > /dev/null 2>&1; do sleep 1; done\" || {\n echo \"ERROR: NATS server is not ready\"\n exit 1\n }\n echo \"✓ NATS is ready\"\n else\n echo \"Skipping NATS health check (NATS_MONITOR_URL not set)\"\n fi\n\n # Wait for Qdrant server (if QDRANT_HTTP_URL is set)\n if [ -n \"$QDRANT_HTTP_URL\" ]; then\n echo \"Waiting for Qdrant server at $QDRANT_HTTP_URL...\"\n timeout 30 bash -c \"until curl -sf $QDRANT_HTTP_URL/healthz > /dev/null 2>&1; do sleep 1; done\" || {\n echo \"ERROR: Qdrant server is not ready at $QDRANT_HTTP_URL\"\n exit 1\n }\n echo \"✓ Qdrant is ready\"\n else\n echo \"Skipping Qdrant health check (QDRANT_HTTP_URL not set)\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Initializing Workspace\"\n echo \"=========================================\"\n\n # Initialize workspace structure\n mkdir -p /workspace/.pantheon\n echo \"✓ Ensured .pantheon directory exists\"\n\n # Create .env.example template if not exists\n if [ ! -f /workspace/.env.example ]; then\n cat > /workspace/.env.example << 'EOF'\n# ========================================\n# Pantheon API Keys Configuration\n# ========================================\n#\n# This is a template file. Your actual config is in .env\n# If you need to reset your configuration, copy this file to .env\n#\n# After editing .env, click the reload button (🔄) to apply changes without restarting.\n# Priority: .env > System defaults > settings.json\n#\n# ========================================\n\n# OpenAI API Key (GPT-4, GPT-3.5, etc.)\n# Uncomment and set your own key to use your OpenAI account\n#OPENAI_API_KEY=sk-your-openai-key-here\n\n# Anthropic API Key (Claude models)\n# Uncomment and set your own key to use your Anthropic account\n#ANTHROPIC_API_KEY=sk-ant-your-anthropic-key-here\n\n# Google Gemini API Key\n# Uncomment and set your own key to use your Google account\n#GEMINI_API_KEY=your-gemini-key-here\n\n# DeepSeek API Key\n#DEEPSEEK_API_KEY=your-deepseek-key-here\n\n# ========================================\n# Advanced Configuration (Optional)\n# ========================================\n\n# Custom LiteLLM endpoint\n#LITELLM_BASE_URL=https://your-litellm-proxy.com\n\n# Debug mode\n#DEBUG=false\n\n# ========================================\n# Notes:\n# - If you don't set these keys, system default keys will be used\n# - Using default keys will deduct quota from your account\n# - After editing .env, click reload (🔄) to apply changes\n# - .env is gitignored and won't be committed\n# ========================================\nEOF\n echo \"✓ Created .env.example template\"\n else\n echo \"✓ .env.example already exists\"\n fi\n\n # Auto-create .env from .env.example if not exists\n if [ ! -f /workspace/.env ]; then\n cp /workspace/.env.example /workspace/.env\n echo \"✓ Created .env from template (auto-copied from .env.example)\"\n echo \" → Edit /workspace/.env to configure your API keys\"\n echo \" → Click reload button (🔄) after editing to apply changes\"\n else\n echo \"✓ .env configuration file already exists\"\n fi\n\n echo \"\"\n echo \"=========================================\"\n echo \"Starting Pantheon ChatRoom\"\n echo \"=========================================\"\n\n # Execute the command with ID_HASH parameter\n if [ $# -eq 0 ]; then\n # No arguments provided, use default command with ID_HASH\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\"\n else\n # Arguments provided, pass them to pantheon.chatroom with ID_HASH\n # This ensures ID_HASH is always used for stable service_id generation\n exec python -m pantheon.chatroom --id_hash=\"${ID_HASH}\" \"$@\"\n fi\nfi\n"}}, "pantheon/utils/llm_catalog.json": {"9bd47ed749befc7ee44a2f956b71a2bfc3b6f34b": {"t": 1785846819.0510886, "n": 77725, "h": "1dfd4dce2b3c09d4", "c": "{\n \"version\": 1,\n \"providers\": {\n \"openai\": {\n \"display_name\": \"OpenAI\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://api.openai.com/v1\",\n \"api_key_env\": \"OPENAI_API_KEY\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_completion_tokens\",\n \"responses_output_token_param\": \"max_output_tokens\",\n \"responses_required_models\": {\n \"contains\": [\n \"codex\"\n ],\n \"suffixes\": [\n \"-pro\"\n ]\n },\n \"models\": {\n \"gpt-5.6-sol\": {\n \"max_input_tokens\": 1050000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 5.0,\n \"output_cost_per_million\": 30.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.6-terra\": {\n \"max_input_tokens\": 1050000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.6-luna\": {\n \"max_input_tokens\": 1050000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 6.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.5\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 12.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.4\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.4-mini\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 1.2,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.4-nano\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.2\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5.2-codex\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5-mini\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 1.2,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-5-nano\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 0.1,\n \"output_cost_per_million\": 0.4,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gpt-image-2\": {\n \"mode\": \"image_generation\",\n \"max_input_tokens\": 0,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0,\n \"output_cost_per_million\": 0,\n \"cost_per_image\": 0,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"gpt-image-1\": {\n \"mode\": \"image_generation\",\n \"max_input_tokens\": 0,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0,\n \"output_cost_per_million\": 0,\n \"cost_per_image\": 0.04,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"gpt-image-1.5\": {\n \"mode\": \"image_generation\",\n \"max_input_tokens\": 0,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0,\n \"output_cost_per_million\": 0,\n \"cost_per_image\": 0.04,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"chatgpt-image-latest\": {\n \"mode\": \"image_generation\",\n \"max_input_tokens\": 0,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0,\n \"output_cost_per_million\": 0,\n \"cost_per_image\": 0.04,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"dall-e-3\": {\n \"mode\": \"image_generation\",\n \"max_input_tokens\": 0,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0,\n \"output_cost_per_million\": 0,\n \"cost_per_image\": 0.04,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"text-embedding-3-large\": {\n \"mode\": \"embedding\",\n \"max_input_tokens\": 8191,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0.13,\n \"output_cost_per_million\": 0,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"text-embedding-3-small\": {\n \"mode\": \"embedding\",\n \"max_input_tokens\": 8191,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0.02,\n \"output_cost_per_million\": 0,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"whisper-1\": {\n \"mode\": \"audio_transcription\",\n \"max_input_tokens\": 0,\n \"max_output_tokens\": 0,\n \"input_cost_per_million\": 0,\n \"output_cost_per_million\": 0,\n \"supports_vision\": false,\n \"supports_function_calling\": false\n },\n \"codex-mini-latest\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 1.5,\n \"output_cost_per_million\": 6.0,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"anthropic\": {\n \"display_name\": \"Anthropic\",\n \"sdk\": \"anthropic\",\n \"base_url\": \"https://api.anthropic.com\",\n \"api_key_env\": \"ANTHROPIC_API_KEY\",\n \"openai_compatible\": false,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"claude-fable-5\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 10.0,\n \"output_cost_per_million\": 50.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": false\n },\n \"claude-opus-4-8\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 5.0,\n \"output_cost_per_million\": 25.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true\n },\n \"claude-opus-4-7\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 5.0,\n \"output_cost_per_million\": 25.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true\n },\n \"claude-opus-4-6\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 5.0,\n \"output_cost_per_million\": 25.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true\n },\n \"claude-opus-4-5-20251101\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 5.0,\n \"output_cost_per_million\": 25.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true\n },\n \"claude-opus-4-20250514\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 32000,\n \"input_cost_per_million\": 15.0,\n \"output_cost_per_million\": 75.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true,\n \"deprecated\": true,\n \"retirement_date\": \"2026-06-15\"\n },\n \"claude-sonnet-5\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": false\n },\n \"claude-sonnet-4-6\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true\n },\n \"claude-sonnet-4-5-20250929\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true\n },\n \"claude-sonnet-4-20250514\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 16000,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": true,\n \"supports_assistant_prefill\": true,\n \"deprecated\": true,\n \"retirement_date\": \"2026-06-15\"\n },\n \"claude-haiku-4-5\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 5.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n }\n }\n },\n \"gemini\": {\n \"display_name\": \"Google Gemini\",\n \"sdk\": \"google-genai\",\n \"base_url\": \"https://generativelanguage.googleapis.com\",\n \"api_key_env\": \"GEMINI_API_KEY\",\n \"openai_compatible\": false,\n \"chat_output_token_param\": \"max_output_tokens\",\n \"models\": {\n \"gemini-3.1-pro-preview\": {\n \"max_input_tokens\": 2000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3-pro-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3.5-flash\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 2.5,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3-flash-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-2.5-pro\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 1.25,\n \"output_cost_per_million\": 10.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-2.5-flash\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-2.5-flash-lite\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.075,\n \"output_cost_per_million\": 0.3,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3-pro-image-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"mode\": \"multimodal_image\",\n \"supports_vision\": true,\n \"supports_function_calling\": false\n },\n \"gemini-3.1-flash-image-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"mode\": \"multimodal_image\",\n \"supports_vision\": true,\n \"supports_function_calling\": false\n },\n \"gemini-2.5-flash-image\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"mode\": \"multimodal_image\",\n \"supports_vision\": true,\n \"supports_function_calling\": false\n }\n }\n },\n \"deepseek\": {\n \"display_name\": \"DeepSeek\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://api.deepseek.com/v1\",\n \"api_key_env\": \"DEEPSEEK_API_KEY\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"deepseek-v4-pro\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 393216,\n \"input_cost_per_million\": 0.435,\n \"output_cost_per_million\": 0.87,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"deepseek-v4-flash\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 393216,\n \"input_cost_per_million\": 0.14,\n \"output_cost_per_million\": 0.28,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n }\n }\n },\n \"zai\": {\n \"display_name\": \"Z.ai (Zhipu)\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://open.bigmodel.cn/api/paas/v4\",\n \"api_key_env\": \"ZAI_API_KEY\",\n \"api_base_env\": \"ZAI_API_BASE\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"glm-5.2\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 1.4,\n \"output_cost_per_million\": 4.4,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"glm-5.1\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 1.4,\n \"output_cost_per_million\": 4.4,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"glm-5\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 1.4,\n \"output_cost_per_million\": 4.4,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false,\n \"deprecated\": true,\n \"deprecation_date\": \"2026-04-20\",\n \"replacement\": \"glm-5.1\"\n },\n \"glm-4.6\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.5,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"glm-4.5\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.5,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"glm-4.5v\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.5,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"glm-4.5-air\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.1,\n \"output_cost_per_million\": 0.4,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"glm-4.5-flash\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.0,\n \"output_cost_per_million\": 0.0,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"minimax\": {\n \"display_name\": \"MiniMax\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://api.minimax.io/v1\",\n \"api_key_env\": \"MINIMAX_API_KEY\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"MiniMax-M2.7\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"MiniMax-M2.7-highspeed\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"MiniMax-M2.5-highspeed\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.5,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"MiniMax-M2.5\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.5,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"MiniMax-M2.1-highspeed\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 1.2,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"MiniMax-M2.1\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 1.2,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"moonshot\": {\n \"display_name\": \"Moonshot (Kimi)\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://api.moonshot.ai/v1\",\n \"api_key_env\": \"MOONSHOT_API_KEY\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"kimi-k2.6\": {\n \"max_input_tokens\": 262144,\n \"max_output_tokens\": 32768,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"kimi-k2.5\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"kimi-k2-0905-preview\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 8192,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"qwen\": {\n \"display_name\": \"Qwen (DashScope)\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n \"api_key_env\": \"DASHSCOPE_API_KEY\",\n \"api_base_env\": \"DASHSCOPE_API_BASE\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"qwen3.7-max\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 7.5,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen3.7-max-2026-05-20\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 7.5,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen3-max\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 7.5,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen3-max-2026-01-23\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 7.5,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen3-235b-a22b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 4.0,\n \"output_cost_per_million\": 16.0,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen3-32b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.7,\n \"output_cost_per_million\": 2.8,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen3-30b-a3b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.35,\n \"output_cost_per_million\": 1.4,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen-max\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen-plus\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.8,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen-turbo\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 8192,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen-vl-max\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen-vl-plus\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 8192,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwq-plus\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"groq\": {\n \"display_name\": \"Groq\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://api.groq.com/openai/v1\",\n \"api_key_env\": \"GROQ_API_KEY\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_completion_tokens\",\n \"models\": {\n \"openai/gpt-oss-120b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"openai/gpt-oss-20b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.075,\n \"output_cost_per_million\": 0.3,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"groq/compound\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 8192,\n \"input_cost_per_million\": 0.0,\n \"output_cost_per_million\": 0.0,\n \"supports_vision\": false,\n \"supports_function_calling\": false,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"llama-3.3-70b-versatile\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 32768,\n \"input_cost_per_million\": 0.59,\n \"output_cost_per_million\": 0.79,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"meta-llama/llama-4-scout-17b-16e-instruct\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 8192,\n \"input_cost_per_million\": 0.11,\n \"output_cost_per_million\": 0.34,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen/qwen3-32b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 40960,\n \"input_cost_per_million\": 0.29,\n \"output_cost_per_million\": 0.59,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"llama-3.1-8b-instant\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.05,\n \"output_cost_per_million\": 0.08,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"openrouter\": {\n \"display_name\": \"OpenRouter\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://openrouter.ai/api/v1\",\n \"api_key_env\": \"OPENROUTER_API_KEY\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"x-ai/grok-4.5\": {\n \"max_input_tokens\": 500000,\n \"max_output_tokens\": 32768,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 6.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"qwen/qwen3.7-max\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 7.5,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"x-ai/grok-4.3\": {\n \"max_input_tokens\": 256000,\n \"max_output_tokens\": 32768,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"google/gemini-3.5-flash\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 2.5,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"mistralai/mistral-medium-3-5\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.4,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"openai/gpt-oss-120b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.09,\n \"output_cost_per_million\": 0.45,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"anthropic/claude-sonnet-4-6\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 16000,\n \"input_cost_per_million\": 3.17,\n \"output_cost_per_million\": 15.83,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"google/gemini-2.5-flash\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.16,\n \"output_cost_per_million\": 0.63,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"deepseek/deepseek-chat\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 8192,\n \"input_cost_per_million\": 0.28,\n \"output_cost_per_million\": 1.16,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"meta-llama/llama-3.3-70b-instruct\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 32768,\n \"input_cost_per_million\": 0.1,\n \"output_cost_per_million\": 0.1,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"mistral\": {\n \"display_name\": \"Mistral AI\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://api.mistral.ai/v1\",\n \"api_key_env\": \"MISTRAL_API_KEY\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"mistral-medium-3-5\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.4,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"mistral-large-2512\": {\n \"max_input_tokens\": 262144,\n \"max_output_tokens\": 262144,\n \"input_cost_per_million\": 0.5,\n \"output_cost_per_million\": 1.5,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"mistral-small-2603\": {\n \"max_input_tokens\": 262144,\n \"max_output_tokens\": 262144,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"devstral-2\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.12,\n \"output_cost_per_million\": 0.36,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"mistral-large-latest\": {\n \"max_input_tokens\": 262144,\n \"max_output_tokens\": 262144,\n \"input_cost_per_million\": 0.5,\n \"output_cost_per_million\": 1.5,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"mistral-medium-latest\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.4,\n \"output_cost_per_million\": 2.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"mistral-small-latest\": {\n \"max_input_tokens\": 262144,\n \"max_output_tokens\": 262144,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"codestral-latest\": {\n \"max_input_tokens\": 256000,\n \"max_output_tokens\": 256000,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 0.9,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"open-mistral-nemo\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 0.02,\n \"output_cost_per_million\": 0.04,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n }\n }\n },\n \"together_ai\": {\n \"display_name\": \"Together AI\",\n \"sdk\": \"openai\",\n \"base_url\": \"https://api.together.xyz/v1\",\n \"api_key_env\": \"TOGETHER_API_KEY\",\n \"api_base_env\": \"TOGETHER_API_BASE\",\n \"openai_compatible\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {\n \"Qwen/Qwen3.7-Max\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 7.5,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"deepseek-ai/DeepSeek-V4-Pro\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 393216,\n \"input_cost_per_million\": 0.435,\n \"output_cost_per_million\": 0.87,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": true\n },\n \"moonshotai/Kimi-K2.6\": {\n \"max_input_tokens\": 262144,\n \"max_output_tokens\": 32768,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"zai-org/GLM-5.1\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 1.4,\n \"output_cost_per_million\": 4.4,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"MiniMaxAI/MiniMax-M2.7\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 131072,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 4.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"openai/gpt-oss-20b\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.075,\n \"output_cost_per_million\": 0.3,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"Qwen/Qwen3.5-397B-A17B\": {\n \"max_input_tokens\": 262144,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.6,\n \"output_cost_per_million\": 3.6,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"deepseek-ai/DeepSeek-V3.1\": {\n \"max_input_tokens\": 128000,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.6,\n \"output_cost_per_million\": 1.7,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"meta-llama/Llama-3.3-70B-Instruct-Turbo\": {\n \"max_input_tokens\": 131072,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 0.88,\n \"output_cost_per_million\": 0.88,\n \"supports_vision\": false,\n \"supports_function_calling\": true,\n \"supports_response_schema\": false,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"deepseek-ai/DeepSeek-R1\": {\n \"max_input_tokens\": 163839,\n \"max_output_tokens\": 16384,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 7.0,\n \"supports_vision\": false,\n \"supports_function_calling\": false,\n \"supports_response_schema\": false,\n \"supports_reasoning\": true,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": false,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n }\n }\n },\n \"codex\": {\n \"display_name\": \"Codex (OAuth)\",\n \"sdk\": \"codex\",\n \"base_url\": \"https://chatgpt.com/backend-api\",\n \"api_key_env\": \"\",\n \"openai_compatible\": false,\n \"auth_mode\": \"oauth\",\n \"responses_output_token_param\": \"max_output_tokens\",\n \"models\": {\n \"gpt-5.6-sol\": {\n \"max_input_tokens\": 1050000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 5.0,\n \"output_cost_per_million\": 30.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"gpt-5.6-terra\": {\n \"max_input_tokens\": 1050000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"gpt-5.6-luna\": {\n \"max_input_tokens\": 1050000,\n \"max_output_tokens\": 128000,\n \"input_cost_per_million\": 1.0,\n \"output_cost_per_million\": 6.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"gpt-5.5\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 3.0,\n \"output_cost_per_million\": 12.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"gpt-5.4\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"gpt-5.4-mini\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 64000,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 1.2,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"gpt-5.2-codex\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"gpt-5\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 2.0,\n \"output_cost_per_million\": 8.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n },\n \"o4-mini\": {\n \"max_input_tokens\": 200000,\n \"max_output_tokens\": 100000,\n \"input_cost_per_million\": 1.1,\n \"output_cost_per_million\": 4.4,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true\n }\n }\n },\n \"ollama\": {\n \"display_name\": \"Ollama (Local)\",\n \"sdk\": \"openai\",\n \"base_url\": \"http://localhost:11434/v1\",\n \"api_key_env\": \"\",\n \"openai_compatible\": true,\n \"local\": true,\n \"chat_output_token_param\": \"max_tokens\",\n \"models\": {}\n },\n \"gemini-cli\": {\n \"display_name\": \"Gemini CLI (OAuth)\",\n \"base_url\": \"https://cloudcode-pa.googleapis.com\",\n \"api_key_env\": \"\",\n \"openai_compatible\": false,\n \"chat_output_token_param\": \"max_output_tokens\",\n \"models\": {\n \"gemini-3.1-pro-preview\": {\n \"max_input_tokens\": 2000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3-pro-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3.5-flash\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.3,\n \"output_cost_per_million\": 2.5,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3-flash-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-2.5-pro\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 1.25,\n \"output_cost_per_million\": 10.0,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-2.5-flash\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": true,\n \"supports_audio_input\": true,\n \"supports_audio_output\": false,\n \"supports_web_search\": true,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-2.5-flash-lite\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.075,\n \"output_cost_per_million\": 0.3,\n \"supports_vision\": true,\n \"supports_function_calling\": true,\n \"supports_response_schema\": true,\n \"supports_reasoning\": false,\n \"supports_audio_input\": false,\n \"supports_audio_output\": false,\n \"supports_web_search\": false,\n \"supports_pdf_input\": true,\n \"supports_computer_use\": false,\n \"supports_assistant_prefill\": false\n },\n \"gemini-3-pro-image-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 2.5,\n \"output_cost_per_million\": 15.0,\n \"mode\": \"multimodal_image\",\n \"supports_vision\": true,\n \"supports_function_calling\": false\n },\n \"gemini-3.1-flash-image-preview\": {\n \"max_input_tokens\": 1000000,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"mode\": \"multimodal_image\",\n \"supports_vision\": true,\n \"supports_function_calling\": false\n },\n \"gemini-2.5-flash-image\": {\n \"max_input_tokens\": 1048576,\n \"max_output_tokens\": 65536,\n \"input_cost_per_million\": 0.15,\n \"output_cost_per_million\": 0.6,\n \"mode\": \"multimodal_image\",\n \"supports_vision\": true,\n \"supports_function_calling\": false\n }\n }\n }\n }\n}\n"}}}}