Codumentor logo Codumentor

LLM Server Manager Plugin

The LLM Server Manager Plugin intercepts LLM connection errors and offers to start the LLM server via an interactive UI card. It provides multi-user synchronization, health monitoring, and automatic shutdown on inactivity.

Overview

The plugin:

  1. Hooks into onLLMError to detect connection failures to the local LLM server
  2. Checks for existing instances before starting new ones
  3. Displays a UI card prompting users to start the server
  4. Tracks server startup progress with real-time updates
  5. Monitors server health with periodic checks
  6. Automatically shuts down the server after configurable inactivity period
  7. Uses a singleton state manager to prevent concurrent start requests
  8. Broadcasts progress to all connected conversations

Backends

The plugin supports two backends for provisioning LLM servers:

BackendDescriptionUse Case
DataCrunch (legacy)Direct DataCrunch API integration with SSH tunnelingSingle-provider setup, existing DataCrunch users
dstackMulti-cloud orchestration via dstackMulti-provider flexibility, automatic cost optimization

What is dstack?

dstack is an open-source GPU orchestration platform that:

When using dstack, you run a dstack server that manages credentials for your cloud providers. The plugin connects to this server to allocate/release GPU instances.

Backend Comparison

FeatureDataCrunchdstack
ProvidersDataCrunch onlyMultiple (Verda, Lambda, RunPod, AWS, GCP, etc.)
ConnectionSSH tunnel to raw IPDirect HTTPS endpoint
Cost optimizationManual profile selectionAutomatic cheapest-available selection
Multi-instance coordinationVia DataCrunch APIVia dstack server (PostgreSQL state)
Setup complexityLower (just API keys)Higher (dstack server required)

Configuration

DataCrunch Backend (Legacy)

plugins:
  - module: codumentor.plugins.llm_server
    class: LLMServerPlugin
    priority: 5
    args:
      enabled: true
      auto_prompt: true
      default_profile: "qwen3-fin02"

      # Backend selection (default: datacrunch)
      backend: "datacrunch"

      # Health checks
      health_check_interval_seconds: 60
      health_check_timeout_seconds: 10
      health_check_max_failures: 3

      # Auto-shutdown
      auto_shutdown_enabled: true
      inactivity_timeout_minutes: 30

      # Instance lifecycle
      check_existing_instances: true

dstack Backend

plugins:
  - module: codumentor.plugins.llm_server
    class: LLMServerPlugin
    priority: 5
    args:
      enabled: true
      auto_prompt: true
      default_profile: "qwen3-72b"

      # Use dstack backend
      backend: "dstack"
      dstack_url: "http://localhost:3000"
      dstack_token: "${DSTACK_TOKEN}"
      dstack_profiles_path: "profiles.yaml"
      dstack_project: "main"

      # Health checks
      health_check_interval_seconds: 60
      health_check_timeout_seconds: 10
      health_check_max_failures: 3

      # Auto-shutdown
      auto_shutdown_enabled: true
      inactivity_timeout_minutes: 30

      # Instance lifecycle
      check_existing_instances: true

Configuration Parameters

Common Parameters

ParameterTypeDefaultDescription
enabledbooleantrueWhether the plugin is enabled
auto_promptbooleantrueAutomatically show UI card when connection errors are detected
default_profilestringnullDefault server profile to use if none specified
priorityinteger5Hook priority (lower = earlier execution)
backendstring"datacrunch"Backend type: "datacrunch" or "dstack"
health_check_interval_secondsinteger60Seconds between health checks
health_check_timeout_secondsinteger10Timeout for health check HTTP requests
health_check_max_failuresinteger3Mark server as ERROR after N consecutive failures
auto_shutdown_enabledbooleantrueEnable auto-shutdown on user inactivity
inactivity_timeout_minutesinteger30Minutes of user inactivity before auto-shutdown
check_existing_instancesbooleantrueCheck for existing instances before starting

dstack-Specific Parameters

ParameterTypeDefaultDescription
dstack_urlstring"http://localhost:3000"URL of the dstack server
dstack_tokenstringnullAuthentication token for dstack (if server requires auth)
dstack_profiles_pathstringnullPath to YAML file with profile definitions
dstack_projectstring"main"dstack project name

How It Works

Error Detection

The plugin detects LLM server connection errors by matching error messages against known patterns:

CONNECTION_ERROR_PATTERNS = [
    "connection refused",
    "econnrefused",
    "localhost:1248",
    "127.0.0.1:1248",
    "apiconnectionerror",
    "failed to connect",
    "connection error",
    "cannot connect",
]

Existing Instance Detection

Before starting a new instance, the plugin checks for existing servers:

DataCrunch backend:

  1. Queries DataCrunch API for instances with status "running" or "starting"
  2. Running instance found: Syncs local state, extracts IP address, broadcasts "started" event
  3. Starting instance found: Waits for it instead of creating duplicate
  4. No instances: Proceeds with new instance creation

dstack backend:

  1. Queries dstack via FleetManager.list_servers()
  2. Running server found: Syncs local state, uses existing endpoint URL
  3. No running servers: Proceeds with new server allocation

This prevents duplicate GPU instances and associated costs.

Health Monitoring

The plugin runs a background scheduler that periodically checks server health:

  1. Queries the /v1/models endpoint (more reliable than /health for model readiness)
  2. Tracks consecutive failures in health_check_failures
  3. After health_check_max_failures failures, marks server as ERROR
  4. Broadcasts error event to all connected UIs

Health check targets by backend:

This detects scenarios where:

Inactivity Detection

The plugin hooks into onInputReceived to track user activity:

  1. Records timestamp of each user message (not LLM/agent activity)
  2. Background task checks: (now - last_user_input) >= inactivity_timeout_minutes
  3. If threshold exceeded, broadcasts auto-shutdown event and stops the server

This ensures expensive GPU instances are stopped when no one is actively using them.

UI Card States

The plugin displays an interactive card with different states:

  1. Prompt: "Server not reachable" with Start/Dismiss buttons
  2. Starting: Spinner with progress message and percentage
  3. Success: Green checkmark with server IP address
  4. Error: Red X with error message and Retry button
  5. Auto-shutdown: Notification before shutdown due to inactivity

Multi-User Synchronization

The plugin uses a class-level singleton state manager to coordinate across multiple conversations:

Server States

UNKNOWN ──(startup check)──> STOPPED or RUNNING (found existing)
STOPPED ──(start request)──> STARTING
STARTING ──(health check pass)──> RUNNING
STARTING ──(timeout/error)──> ERROR
RUNNING ──(health failures)──> ERROR
RUNNING ──(inactivity timeout)──> STOPPING ──> STOPPED
RUNNING ──(stop request)──> STOPPING ──> STOPPED
StateDescription
UNKNOWNInitial state, server status not checked
STOPPEDServer is not running
STARTINGServer startup in progress
RUNNINGServer is running and accessible
STOPPINGServer shutdown in progress
ERRORServer startup or health check failed

State Fields

The ServerState object tracks different fields depending on the backend:

FieldDataCrunchdstackDescription
ip_address-Server IP (used with SSH tunnel)
instance_id-DataCrunch instance ID
endpoint-Full HTTPS URL (e.g., https://gateway.dstack.ai/...)
server_id-dstack run name
profileProfile used for allocation
started_atWhen server reached RUNNING state
is_model_readyWhether /v1/models returns loaded model

REST API Endpoints

The plugin exposes REST endpoints under /ui/v0/plugins/llm_server/:

EndpointMethodDescription
/startPOSTStart the LLM server
/stopPOSTStop/hibernate the server
/statusGETGet current server status
/profilesGETList available server profiles

Start Server

curl -X POST http://localhost:2638/ui/v0/plugins/llm_server/start \
  -H "Content-Type: application/json" \
  -d '{"profile": "qwen3-32b"}'

Response:

{
  "status": "starting",
  "profile": "qwen3-32b",
  "message": "Server startup initiated"
}

Get Status

curl http://localhost:2638/ui/v0/plugins/llm_server/status

Response (DataCrunch backend):

{
  "status": "running",
  "ip_address": "192.168.1.100",
  "profile": "qwen3-32b"
}

Response (dstack backend):

{
  "status": "running",
  "endpoint": "https://gateway.dstack.ai/services/llm-qwen3-72b-a1b2c3d4/",
  "server_id": "llm-qwen3-72b-a1b2c3d4",
  "profile": "qwen3-72b"
}

List Profiles

curl http://localhost:2638/ui/v0/plugins/llm_server/profiles

Response:

{
  "profiles": {
    "qwen3-32b": "Qwen 3 32B with FP8 quantization",
    "llama-70b": "Llama 3 70B instruct"
  }
}

UI Event Types

The plugin emits the following event types:

Event TypeDescription
plugin.llm_server.connection_failedConnection error detected, prompt to start
plugin.llm_server.startingServer startup initiated
plugin.llm_server.progressProgress update during startup
plugin.llm_server.startedServer started successfully
plugin.llm_server.stoppedServer stopped
plugin.llm_server.errorError occurred during operation
plugin.llm_server.auto_shutdownAuto-shutdown initiated due to inactivity

Prerequisites

DataCrunch Backend

API Credentials

export DATACRUNCH_CLIENT_ID="your_client_id"
export DATACRUNCH_CLIENT_SECRET="your_client_secret"

Server Profiles

Server profiles are configured in scripts/llm_server_manager/profiles.json:

{
  "qwen3-32b": {
    "description": "Qwen 3 32B with FP8 quantization",
    "instance_type": "1V100.6V",
    "location": "FIN-02"
  }
}

dstack Backend

1. dstack Server

You need a running dstack server. Use the automated installer:

/usr/local/lib/codumentor/scripts/install-dstack-server.sh install

This installs dstack as a systemd user service with Verda (DataCrunch) backend configured.

For detailed setup instructions, see the dstack Server Setup Guide.

2. Cloud Provider Configuration

Configure dstack with your cloud provider credentials in ~/.dstack/server/config.yml:

projects:
  - name: main
    backends:
      # Verda (if you have an account)
      - type: verda
        creds:
          type: api_key
          client_id: ${VERDA_CLIENT_ID}
          client_secret: ${VERDA_CLIENT_SECRET}

      # Lambda Labs
      - type: lambda
        creds:
          type: api_key
          api_key: ${LAMBDA_API_KEY}

      # RunPod
      - type: runpod
        creds:
          type: api_key
          api_key: ${RUNPOD_API_KEY}

dstack automatically selects the cheapest available provider that meets your resource requirements.

3. Profile Configuration

Create a profiles.yaml file with your model configurations:

profiles:
  qwen3-72b:
    model: "Qwen/Qwen3-72B"
    min_gpu_memory_gb: 80
    gpu_types: [H100, H200, A100_80G]

  qwen3-32b:
    model: "Qwen/Qwen3-32B"
    min_gpu_memory_gb: 48
    gpu_types: [A100, H100, L40S]

  llama3-70b:
    model: "meta-llama/Llama-3-70B-Instruct"
    min_gpu_memory_gb: 80

  codestral-22b:
    model: "mistralai/Codestral-22B-v0.1"
    min_gpu_memory_gb: 48

Profile fields:

Troubleshooting

Plugin Not Loading

Check the logs for plugin loading errors:

grep "LLMServerPlugin" logs/codumentor.log

UI Card Not Appearing

  1. Verify the plugin is enabled in your configuration
  2. Check that auto_prompt is set to true
  3. Ensure the error is a connection error to localhost:1248

Server Not Starting

  1. Verify DataCrunch credentials are set
  2. Check available profiles: python scripts/manage_llm_server.py start --profile list
  3. Check service logs for detailed errors

Health Checks Failing During Startup

The LLM model takes ~6 minutes to load. During this time, health checks will report "No models loaded yet". This is normal—the plugin automatically detects when the model is ready via the /v1/models endpoint.

Auto-Shutdown Triggers During Active Use

Check that your activity is generating onInputReceived events. Only direct user input (not LLM responses or tool executions) resets the inactivity timer. This is by design to prevent agent loops from keeping the server running indefinitely.

Multiple Instances Created

Ensure check_existing_instances: true is set. If backend API calls fail (e.g., network issues), the plugin falls back to allowing start attempts.

dstack Server Connection Failed

  1. Verify dstack server is running: curl http://localhost:3000/api/health
  2. Check dstack_url in configuration matches your server
  3. If using authentication, ensure dstack_token is set correctly
  4. Check dstack server logs for errors

dstack Allocation Fails

  1. Verify cloud provider credentials in ~/.dstack/server/config.yml
  2. Check that at least one provider has available capacity
  3. Ensure your profile's min_gpu_memory_gb is achievable (some providers may not have large GPUs available)
  4. Check dstack server logs: dstack server output or ~/.dstack/server/logs/

Profile Not Found (dstack)

  1. Verify dstack_profiles_path points to a valid YAML file
  2. Check the profile name matches exactly (case-sensitive)
  3. Verify YAML syntax: python -c "import yaml; yaml.safe_load(open('profiles.yaml'))"

CLI Interface

For command-line server management, see the LLM Server CLI.

Common commands:

# Start server with default profile
python scripts/manage_llm_server.py start

# Start with specific profile
python scripts/manage_llm_server.py start --profile qwen3-32b

# Stop/hibernate all instances
python scripts/manage_llm_server.py stop

# List available profiles
python scripts/manage_llm_server.py start --profile list

Architecture

The plugin consists of four layers:

  1. Service Layer (src/codumentor/services/llm_server/): - Core logic for server management - Singleton state manager for coordination - Backend adapters (DataCrunch, dstack) - Instance lifecycle management
  1. GPU Fleet Library (src/gpu_fleet/): - FleetManager protocol for server allocation/release - DstackFleetManager implementation wrapping dstack SDK - Profile loading from YAML - Provider-agnostic interface
  1. Plugin Layer (src/codumentor/plugins/llm_server/): - Hook handlers for error interception and activity tracking - Background scheduler for health and inactivity checks - REST API endpoints - UI event emission
  1. UI Layer (ui/plugins/llm_server/): - Custom element <x-llm-server-card> - Interactive controls for server management - Real-time progress display

Backend Flow

┌─────────────────────────────────────────────────────────────────┐
│                     LLMServerStateManager                        │
│  (Singleton state, backend dispatch, UI event broadcasting)     │
└─────────────────────────────┬───────────────────────────────────┘
                              │
              ┌───────────────┴───────────────┐
              │ backend="datacrunch"          │ backend="dstack"
              ▼                               ▼
┌─────────────────────────┐     ┌─────────────────────────────────┐
│   DataCrunch Backend    │     │    FleetManagerAdapter          │
│   - instance_manager.py │     │    - Wraps gpu_fleet library    │
│   - SSH tunnel required │     │    - HTTPS endpoints (no SSH)   │
│   - profiles.json       │     │    - profiles.yaml              │
└───────────┬─────────────┘     └───────────────┬─────────────────┘
            │                                   │
            ▼                                   ▼
┌───────────────────────┐         ┌─────────────────────────────────┐
│   DataCrunch API      │         │       gpu_fleet Library         │
│                       │         │   - FleetManager protocol       │
└───────────┬───────────┘         │   - DstackFleetManager impl     │
            │                     └───────────────┬─────────────────┘
            ▼                                     │
┌───────────────────────┐                         ▼
│   GPU Instance        │         ┌─────────────────────────────────┐
│   (via SSH tunnel)    │         │       dstack Server             │
└───────────────────────┘         │   - Multi-provider selection    │
                                  │   - Shared state (PostgreSQL)   │
                                  └───────────────┬─────────────────┘
                                                  │
                                  ┌───────────────┴───────────────┐
                                  ▼               ▼               ▼
                               Verda          Lambda          RunPod
                                  │               │               │
                                  ▼               ▼               ▼
                               GPU Instance   GPU Instance   GPU Instance
                               (HTTPS endpoint)

Module Structure

src/codumentor/plugins/llm_server/
├── __init__.py           # Package exports
├── llm_server_plugin.py  # Main plugin class with scheduler integration
├── error_detection.py    # Connection error pattern matching
├── health_check.py       # HTTP health probe utilities (IP and endpoint)
└── scheduler.py          # Background task scheduler

src/codumentor/services/llm_server/
├── __init__.py           # Service exports
├── server_state.py       # Singleton state manager with dual-backend support
├── fleet_adapter.py      # Adapter bridging gpu_fleet with state manager
├── instance_manager.py   # DataCrunch instance operations (legacy)
├── datacrunch_client.py  # DataCrunch API client factory
├── profiles_manager.py   # DataCrunch profile configuration
├── ssh_tunnel.py         # SSH port forwarding (DataCrunch only)
└── exceptions.py         # Custom exceptions

src/gpu_fleet/
├── __init__.py           # Public exports (create_fleet_manager, etc.)
├── interface.py          # FleetManager protocol, LLMServer, Profile dataclasses
├── manager.py            # DstackFleetManager implementation
├── profiles.py           # YAML profile loading
├── factory.py            # create_fleet_manager() entry point
└── exceptions.py         # FleetError hierarchy

Source Code

See Also