Skip to content
This repository was archived by the owner on Jul 30, 2026. It is now read-only.
sukarn-mPublic archive

About

Go port of https://github.com/notBlubbll/umans-dash with opinionated modifications

Resources

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

 

History

21 Commits

Folders and files

Repository files navigation

UMANS-Dash-Go

OpenAI- and Anthropic-compatible proxy for UMANS AI, written in Go. Zero external dependencies.

This is a Go port and opinionated customization of the original Node.js project at https://github.com/notBlubbll/umans-dash.

Dashboard

Dashboard with wallpaper

Features

  • OpenAI-Compatible API — Drop-in for /v1/chat/completions and /v1/models
  • Anthropic Messages API — Pass-through for /v1/messages (Anthropic-compatible clients)
  • Multi-Key Pool — Round-robin key pool with unhealthy marking, cooldowns, and persistence across restarts
  • Automatic Upstream Retry — Retries failed requests on HTTP 500/503 and network failures up to a configurable number of attempts (default 2, range 0–10) with configurable backoff presets (aggressive or conservative), rotating to a fresh key on each attempt. Applies to both OpenAI and Anthropic paths
  • Concurrency Queue — Bounded request queue gated by Concurrency Limit mode (Soft Cap, Hard Cap, or Manual with a custom slider), with soft-limit (limit) and hard-cap (burst) tracking, throttled-503 counter, and rejection when full. A background queue worker with sync.Cond signaling dispatches queued requests when slots free up. A configurable Slot Free Delay (seconds) can pause before freeing a slot after request completion to avoid upstream rate limits
  • Dashboard — Clean UI with usage cards, concurrency monitoring, usage history chart with sortable tables, model management, key management, and configuration
  • API Key Mode — Smart (default), Managed, or Pass-Through mode controlling which API key is used for upstream requests (client key vs. proxy key pool)
  • Empty Stream Detection — Detects when upstream returns HTTP 200 + text/event-stream but sends zero data bytes, and treats it as a retryable error (with configurable retry attempts) instead of forwarding an empty stream to the client
  • Non-Blocking Config Updates — Proxy request handlers snapshot config fields and release the config lock immediately, so settings changes complete instantly even during active LLM completions
  • Bing Wallpaper — Daily rotating UHD (3840px) backgrounds from Bing
  • Wallhaven Wallpaper — Optional high-resolution (≥2560×1440) backgrounds from Wallhaven with JPEG, PNG, and WebP support
  • Automatic Image-Attachment Limit — Caps vision/images per request; excess images are pruned oldest-first before forwarding to UMANS
  • Vision Handoff — Models that can't see images natively (e.g. GLM 5.2) automatically delegate image analysis to a vision-capable model (default umans-coder) and inject the text description into the session context
  • Handoff Image Cache — When vision handoff is enabled, caches image descriptions for 24 hours so repeated images skip re-analysis
  • Thinking Payload Normalization — Rewrites camelCase budgetTokens back to snake_case budget_tokens for UMANS Pydantic compatibility
  • Tool Schema Normalization — Simplifies anyOf/nullable combinators and resolves $ref references before forwarding

Project Layout

umans-dash-go/
├── main.go                # Entry point (config load, HTTP server, graceful shutdown)
├── go.mod                 # Go module definition (stdlib only)
├── src/                   # Proxy package (package proxy)
│   ├── embed.go           # go:embed wrapper for dashboard assets
│   ├── interface/
│   │   ├── dashboard.html # Dashboard UI
│   │   └── dashboard.js   # Dashboard JavaScript (template-rendered)
│   ├── config.go          # Constants, config loading/saving, env overrides
│   ├── upstream.go        # UpstreamClient, HTTP calls to upstream API
│   ├── keypool.go         # API key pool with cooldown/health tracking
│   ├── cache.go           # ImageHandoffCache LRU, hash helpers
│   ├── normalize.go       # Reasoning, tool schema, payload normalization
│   ├── conversation.go    # Conversation tracking, fingerprinting
│   ├── errors.go          # Header/body redaction
│   ├── errors_log.go      # Error log file, HTTP error records
│   ├── retry.go           # Retry loop, backoff presets
│   ├── http.go            # HTTP helpers, SSE, error writers, auth
│   ├── proxy_chat.go      # OpenAI chat completions proxy handler
│   ├── proxy_anthropic.go # Anthropic messages proxy handler
│   ├── queue.go           # Queue dispatch, concurrency limit mode
│   ├── usage.go           # Usage/concurrency fetch, caching
│   ├── handlers.go        # All HTTP handlers
│   ├── wallpaper.go       # Wallpaper download/cache/serve
│   ├── vision.go          # Vision handoff
│   ├── dashboard.go       # Dashboard rendering
│   ├── proxy.go           # NewProxy, ServeHTTP, Shutdown, lifecycle
│   └── types.go           # Type definitions (Config, KeyPool, Proxy, etc.)
├── screenshots/           # Dashboard screenshots
├── .cache/                # Cached wallpaper images (auto-created)
├── .logs/                 # HTTP error logs (auto-created)
├── .config/               # config.json (auto-created, gitignored)
└── AGENTS.md              # Developer guide

Differences from the Original Node.js Version

  • Single Go binary — no Node.js runtime, no npm install, no node_modules
  • Zero external dependencies — uses only the Go standard library
  • Excluded features (present in the upstream original, removed in this port):
    • FreeGen AI wallpaper generator (/api/bg-freegen, FREEGEN_PROMPT, WebSocket integration with freegen.app)
    • Sleev context-compression gateway (SLEEV_ENABLED, SLEEV_GATEWAY_*, binary discovery, OAuth sign-in, lifecycle management)
    • /api/sleev endpoint (dashboard control to enable/disable and check Sleev gateway status)
    • Shell Guard (git-command blocking in tool-call responses, streaming and non-streaming)
    • i18n autotranslation system (/api/i18n, I18N_STRINGS catalog, LOCALE config, one-click autotranslate via umans-flash)
    • Response cache for non-streaming chat (ResponseCache, cacheKey(), /api/cache GET/DELETE, CACHE_TTL/CACHE_MAX_SIZE/CACHE_ENABLED)
    • UMANS app login (EMAIL/PASSWORD/APP_SESSION, loginToApp(), /api/umans/login, /api/umans/logout)
    • Per-model rate limit map (RATE_LIMIT_MAP, enforceRateLimit())
    • Opencode config auto-setup (setupOpencodeConfig(), discoverOpencodeConfigs(): discovers and writes a umans provider entry into opencode.json with reasoning variants, context limits, tool/vision flags, and AGENTS.md/skills.md instructions; backs up existing config on first run)
    • models.dev catalog integration (getModelsDevCatalog(), findModelsDevEntry(): fetches models.dev to derive reasoning mode and metadata for the opencode provider entry)
    • Automatic dashboard browser launch on first run (xdg-open/open/start when opencode config is first created)
    • Test Chat panel in the dashboard
    • SS Mode (screenshot-safe blur/masking)
    • SVG-filter glassmorphism (feDisplacementMap/feColorMatrix; replaced with CSS backdrop-filter)
    • SQLite usage-history cache (.cache/usage.db, node:sqlite/bun:sqlite)
  • Default value differences (both ports have the feature, but defaults differ):
    • Vision handoff default model: umans-kimi-k2.7 upstream, umans-coder here
    • Vision handoff default state: enabled (true) upstream, disabled (false) here
    • Wallpaper source default: freegen upstream, bing here
  • Added features (not in the upstream original):
    • API Key Mode (Smart / Managed / Pass-Through) controlling which key is sent upstream
    • Concurrency Limit mode (Soft Cap / Hard Cap / Manual with slider), persisted to config
    • Slot Free Delay (configurable delay before freeing a concurrency slot)
    • Configurable Retry Attempts (slider, 0-10, default 2) with Backoff Strategy presets (aggressive/conservative) replacing hardcoded 10-retry count and flat 3s backoff
    • Configurable Request Timeout (slider, 30s-30m, default 15m, applied live without restart)
    • Anthropic path retry support (upstream /v1/messages is single-attempt only; this port retries on HTTP 500/503 and network failures with key rotation, matching the OpenAI path)
    • Priority status card replacing Throttled card in the dashboard (always visible, red when Low priority)
    • Usage Limits card consolidating concurrency usage progress bar and priority budget inline bars with service mode banner
    • Service Status card with per-model health breakdown (3 view variants: Table/Bars/Heatmap, color thresholds for uptime/TTFT/TPS)
    • Empty SSE stream detection and retry (detects HTTP 200 + text/event-stream with zero data bytes; prevents "empty stream" client errors)
    • Non-blocking config updates (request handlers snapshot config fields and release the lock immediately)
    • Vision Handoff Image Cache (SHA-256 keyed LRU, 24h TTL, configurable)
    • /v1/models/info endpoint exposing the raw upstream model catalog
    • UHD Bing wallpaper (3840px peapix resolution upgrade)
    • Wallhaven resolution filter (atleast=2560x1440) with JPEG/PNG/WebP content-type detection
    • Queue-full responses return HTTP 429 Too Many Requests with Retry-After header to discourage immediate retries
    • Response-writer tracker with abort/hijack guards prevents superfluous WriteHeader panics and protects streaming responses from timeout middleware races
    • Unified dispatch path with sync.Cond-based queue worker: ProcessQueue reserves slots under queueMu before launching runDispatch goroutines, eliminating gate overshoot; dispatchItem used only for the no-limit fast path
    • OnRequestComplete uses a queueDone-aware goroutine for slot-free delay instead of blocking time.Sleep, allowing shutdown to cancel pending delays without timer/lock deadlocks
    • Idempotent Shutdown via sync.Once on queueDone close; worker drains before HTTP server shutdown
    • GetEffectiveConcurrency accepts override int parameter to avoid recursive configMu.RLock() when called from gateLimit() or HandleConfigPost
    • HandleConfigPost releases configMu before calling signalQueue() to prevent lock-order inversion
    • Timeout middleware uses compare-and-set on tw.written to claim the response exclusively before writing the timeout error, preventing the "superfluous response.WriteHeader" log warning
    • WriteJSON checks IsCommitted() before writing in the non-SSE branch to skip writes on already-committed trackers
    • Request-context propagation through upstream calls so client disconnects cancel in-flight work
    • Configurable vision-handoff concurrency cap (default 4) to prevent goroutine explosion on multi-image requests
    • Shared catalogClient for upstream catalog/models/user-info fetches with connection reuse
    • Catalog singleflight with stale fallback to prevent thundering-herd refreshes
    • Effective-concurrency cache and gate-limit cache to reduce lock churn under load
    • Shutdown queue draining: rejects queued requests with 503 before draining active requests
    • Redesigned dashboard UI (unified refresh cycle, concurrency card with burst-zone visualization, sortable usage history with per-model drill-down)
    • Service status proxy endpoints (/api/umans/status with 1-min cache, /api/umans/status-history with 5-min cache) forwarding raw JSON from upstream /v1/status and /v1/status/history
    • Usage Limits dashboard card consolidating concurrency usage and priority budget with service mode banner
    • Service Status dashboard card with Table/Bars/Heatmap view variants and color-coded health thresholds (uptime, TTFT, TPS)
  • Shared features (present in both, no behavioral difference documented):
    • DISABLED_MODELS config field, tool schema normalization, thinking payload normalization, reasoning-level adaptive thinking injection
  • Wallpaper sources: none, bing, or wallhaven only (no freegen)
  • Default listen address: 127.0.0.1:8084

Quick Start

Prerequisites

  • Go 1.22 or later

1. Get a UMANS API Key

  1. Go to app.umans.ai and sign up or log in.
  2. Navigate to the API Keys section.
  3. Click Create API Key — you'll get a key starting with sk-....
  4. Copy this key — it will be used by the proxy.

2. Configure the Proxy

Edit .config/config.json and set your API key:

{
  "API_KEY": "sk-..."
}

Or via environment variable:

export UMANS_API_KEY=sk-...

3. Build and Run

go build -o umans-dash-go .
./umans-dash-go

For development you can also run directly:

go run .

4. Add Models

Edit .config/config.json and add the model IDs you want to expose to the ENABLED_MODELS array:

{
  "ENABLED_MODELS": ["qwen3-coder", "deepseek-v4-pro"]
}

Restart the proxy for the change to take effect.

5. Use with Any OpenAI Client

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: 'ignored',
  baseURL: 'http://127.0.0.1:8084/v1'
});

const response = await client.chat.completions.create({
  model: 'qwen3-coder', // must be in your enabled models list
  messages: [{ role: 'user', content: 'Hello!' }]
});

Anthropic-compatible clients

The proxy also exposes /v1/messages for Anthropic-format clients:

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({
  apiKey: 'ignored',
  baseURL: 'http://127.0.0.1:8084/v1'
});

const response = await client.messages.create({
  model: 'umans-kimi-k2.7',
  max_tokens: 4096,
  messages: [{ role: 'user', content: 'Hello!' }]
});

Dashboard

Open http://127.0.0.1:8084 in your browser.

Unified refresh cycle: Status, usage, concurrency, history, and service status all refresh together on the user-selected Automatic Refresh interval. The interval is persisted in localStorage and restored on page load (default 30s).

Usage Limits Card

  • Consolidates concurrency usage progress bar and priority budget inline bars
  • Service mode banner shown when upstream is in low-interactivity mode
  • Collapsible (expanded by default); remains expanded on mobile

Current Concurrency Card

  • 4 stat cards: Active (green), Queued (blue), Limit (soft, yellow), Burst (hard cap, orange)
  • Progress bar with solid fill (proxy active) and dotted overlay (upstream concurrent)
  • Bottom-border zone markers: yellow for soft-cap region, orange for burst region
  • The progress bar scales to the effective gate (barMax): Soft Cap → limit, Hard Cap → hard_cap, Manual → manualLimit. Zones (green→orange gradient) are shown when barMax > limit
  • Percentage shows value relative to the effective gate
  • Collapsible

5-Hour Window Card

  • 6 static stat cards: Requests, Throttled, Cached %, Start Time, Tokens In, Tokens Out
  • Collapsible

Usage History Card

  • Bar chart with Y-axis labels, dashed grid lines, and X-axis labels
  • Click a bar to filter the table to that date
  • Table shows consolidated per-date rows (Date, Requests, Tokens In, Tokens Out, Cache %, Peak) with sortable headers. Peak shows peak → weighted peak with an arrow (same as Requests)
  • Click a row to expand a per-model detail table (Model, Requests, Tokens In, Tokens Out, Cache %, Peak) with its own sortable headers
  • Metric toggle (Tokens/Requests) controls chart scale and default sort
  • Status legend shown only in Requests mode; hidden in Tokens mode
  • Client-side cache — 30d of data is fetched once per granularity and cached for 5 minutes. Switching between 24h, 7d, and 30d ranges is instant (client-side date filtering, no upstream call)

Service Status Card

  • Overall health stats and per-model breakdown
  • 3 view variants: Table (default), Bars, Heatmap — all fully dynamic from the upstream response
  • Color thresholds: uptime ≥99.5% green / ≥99% yellow / below red; TTFT ≤1.5s green / ≤3s yellow / above red; TPS ≥100 green / ≥50 yellow / below red
  • Collapsible

Quick Settings (expanded)

  • Automatic Refresh — 30s / 1m / 2m / 5m (=298s) interval selector; persisted to localStorage
  • Wallpaper — None / Bing / Wallhaven
  • Concurrency Limit — Soft Cap / Hard Cap / Manual selector. Manual reveals a slider (1 to hard cap) for a custom concurrency limit. Persisted in config (CONCURRENCY_LIMIT_MODE, MANUAL_CONCURRENCY_LIMIT)
  • Slot Free Delay — Slider (0–60s, default 2) that delays freeing a concurrency slot after a request completes. Persisted in config (SLOT_FREE_DELAY)
  • Request Timeout — Slider (30s–30m, default 15m) for upstream request timeout, applied live without restart. Positioned above Retry Attempts
  • API Key — Smart / Managed / Pass-Through mode selector
  • Manage API Keys — Button to open the key management modal (visible when mode is Smart or Managed; hidden in Pass-Through)
  • Vision Handoff — Toggle image handoff for vision-incapable models
  • Handoff Cache — Toggle caching of vision handoff image analyses (shown only when Vision Handoff is enabled)
  • Sections collapse with a chevron icon that swaps between bi-chevron-down (expanded) and bi-chevron-right (collapsed)

Quick Actions (expanded)

  • Health check, connection test, manual refresh, restart proxy

Models (expanded)

  • View and toggle models from the catalog

Environment (expanded)

  • Runtime, Port, Started At

Wallpaper Rendering

  • Desktop: background-size: cover (fills the viewport)
  • Mobile (≤575px): background-size: contain (shows the full image centered)
  • Server-side CSS injection includes full background properties (no-repeat, center, fixed, base color)

Header Bar

  • User ID (click-to-reveal, masked by default) and online status indicator

Mobile Layout

  • All sections except Usage Limits collapse by default on screens ≤575px
  • Right-column sections (Quick Settings, Quick Actions, Models, Environment) remain accessible via collapse toggles

API Key Mode

The proxy supports three modes for selecting which API key is sent to the upstream UMANS API on each request. The mode is configurable from the dashboard's Quick Settings panel and persisted in config.json via the API_KEY_MODE field.

Mode Behavior Authorization
Smart (default) Uses the client's API key if one is provided in the request (Authorization: Bearer <key> or X-Api-Key); falls back to the proxy's own key pool if no client key is present Accepts all requests
Managed Always uses the proxy's own key pool, ignoring any client-supplied key Validates client requests against the API_KEYS allow-list (if configured); open if no allow-list is set
Pass-Through Always uses the client's API key, disabling the proxy's key management entirely Accepts any request that includes an API key

Dashboard upstream calls (usage, concurrency, history) adapt to the active mode:

  • Pass-Through: uses the last-known-good client key
  • Smart: prefers the last-known-good client key, falls back to the pool key
  • Managed: uses the pool key

The Manage API Keys button in Quick Settings is hidden in Pass-Through mode.

Vision Handoff

Some UMANS models (e.g. umans-glm-5.2, umans-glm-5.1) are advertised with supports_vision: "via-handoff" — they cannot process images natively. The proxy transparently bridges this gap:

  1. When a request to a via-handoff model contains images, the proxy extracts them (OpenAI image_url and Anthropic image parts, including nested tool-result blocks).
  2. Each image is sent to the handoff model (default umans-coder) with an analysis prompt.
  3. If the handoff cache is enabled, the proxy checks a SHA-256 hash of the image data URI against the ImageHandoffCache first. On cache hit, the cached description is reused without calling upstream. On miss, the upstream is called and the result is cached for 24 hours.
  4. Images are analyzed in parallel and replaced in-place with {type: "text", text: "[Image content — analyzed by vision module, shown as text because the active model cannot see images:]\n<description>"} blocks.
  5. The modified payload (now text-only) is forwarded to the originally requested model.

The handoff applies to both the OpenAI (/v1/chat/completions) and Anthropic (/v1/messages) paths, running after model resolution and before the upstream call.

Config keys:

Field Description Default
VISION_HANDOFF_ENABLED Toggle the handoff for all via-handoff models false
VISION_HANDOFF_MODEL Vision-capable model used to analyze images umans-coder
VISION_HANDOFF_PROMPT Custom analysis system prompt (empty = built-in) —
VISION_HANDOFF_CACHE_ENABLED Enable caching of vision handoff image analyses false
VISION_HANDOFF_CACHE_TTL TTL for cached vision handoff analyses 24h

The built-in prompt instructs the handoff model to produce a factual, third-person description of the image as a single coherent paragraph — covering image type, visible elements and their spatial arrangement, exact transcription of text/code, and salient technical details.

API Endpoints

Method Path Description
GET /healthz Proxy health check (vision handoff status + cache stats)
GET /v1/models OpenAI-format model list with pricing and context length
GET /v1/models/info Raw model catalog
POST /v1/chat/completions OpenAI-format chat completions
POST /v1/messages Anthropic Messages API (pass-through to upstream)
GET /api/config Get proxy configuration
POST /api/config Update proxy configuration
GET /api/validate Validate API key
GET /api/models List enabled models
GET /api/umans/usage UMANS usage data (supports ?fresh=1 to bypass cache)
GET /api/umans/usage-history UMANS usage history (supports from, to, granularity, scope; ?fresh=1 bypasses cache)
GET /api/umans/concurrency Concurrency sessions, limit, hard_cap, active count & queue depth (supports ?fresh=1)
GET /api/umans/user UMANS user info
GET /api/umans/status UMANS service status (supports ?fresh=1 to bypass cache)
GET /api/umans/status-history UMANS status history (supports from, to, granularity, metric, model; ?fresh=1 bypasses cache)
GET /api/keys List API keys
POST /api/keys Add/update/delete API keys
GET /api/bg Daily Bing wallpaper
GET /api/bg-wallhaven Random Wallhaven wallpaper
POST /api/restart Restart the proxy

Configuration

.config/config.json supports:

Field Description Default
LISTEN_ADDR Proxy listen address 127.0.0.1:8084
UPSTREAM_BASE_URL UMANS API URL https://api.code.umans.ai/v1
API_KEY UMANS API key (sk-*) —
KEYS Array of additional API keys for the key pool (name + key) []
REQUEST_TIMEOUT Upstream request timeout 15m
ENABLED_MODELS Array of model IDs to expose []
DISABLED_MODELS Array of model IDs to hide from the catalog []
MODEL_DISPLAY_NAMES Custom display names per model {}
API_KEYS Array of allowed proxy API keys (auth) []
OVERRIDE_CONCURRENCY Override concurrent sessions value (0 = auto-detect from API; capped to min of override and upstream hard_cap) 0
MAX_IMAGES Maximum image attachments per forwarded request; oldest images are dropped first 9
VISION_HANDOFF_ENABLED Enable image handoff for vision-incapable models false
VISION_HANDOFF_MODEL Vision-capable model used to analyze images during handoff umans-coder
VISION_HANDOFF_PROMPT Custom analysis prompt for the handoff model (empty = built-in) —
VISION_HANDOFF_CACHE_ENABLED Enable caching of vision handoff image analyses false
VISION_HANDOFF_CACHE_TTL TTL for cached vision handoff analyses 24h
wallpaperSource Dashboard wallpaper source: none, bing, or wallhaven bing
API_KEY_MODE API key selection mode: smart, managed, or passthrough smart
CONCURRENCY_LIMIT_MODE Concurrency gating mode: soft (soft cap), hard (hard cap), or manual (custom via slider) soft
MANUAL_CONCURRENCY_LIMIT Custom concurrency limit when mode is manual (0 = auto-initialize to soft cap on first use) 0
SLOT_FREE_DELAY Delay in seconds before freeing a concurrency slot after a request completes (0 = immediate) 2
BURST_MODE Deprecated. Kept for config migration + rollback safety. true when mode is hard, false otherwise false

Building and Development

# Compile check
go build ./...

# Static analysis
go vet ./...

# Run directly
go run .

# Build binary
go build -o umans-dash-go .

License

This project is licensed under the MIT License — see LICENSE for details.

About

Go port of https://github.com/notBlubbll/umans-dash with opinionated modifications

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages