ai

package module
v1.832.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 1, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

README

Hanzo AI

ai

The AI control plane for the Open AI Cloud — model hub, native Go routing, and RAG in one binary.

Build Release GHCR License Discord

Forked from Casibase (Apache-2.0).

What this is

ai is the canonical AI control plane for the Hanzo platform — model routing, RAG, model hub, and MCP management, implemented in pure Go. It speaks the OpenAI-compatible /v1 API (/v1/chat/completions, /v1/models), routes 66+ models straight to upstream providers, and meters every request. Three auth modes (IAM API key hk-*, JWT, provider key sk-*). KMS-resolved provider secrets, org-scoped. Per-request usage tracking, fire-and-forget to IAM.

Renamed from hanzoai/cloud on 2026-05-19 when the unified binary took the cloud name (HIP-0106); ai now mounts as the ai subsystem inside hanzoai/cloud.

Implements HIP-0037 (AI Cloud Platform) and HIP-0106 (Unified Cloud Binary — ai subsystem).

Quick start

Call the hosted control plane:

curl -H "Authorization: Bearer hk-YOUR-API-KEY" \
  https://api.hanzo.ai/v1/chat/completions \
  -d '{"model":"zen4-pro","messages":[{"role":"user","content":"Hello"}]}'

Run it yourself (pin a released vX.Y.Z — never :latest):

docker pull ghcr.io/hanzoai/ai:vX.Y.Z
docker run -p 8000:8000 ghcr.io/hanzoai/ai:vX.Y.Z

Build from source:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o cloud-api-server .
./cloud-api-server

Architecture

ai implements ZAP (Zero-overhead API Protocol) — a native Go routing layer that connects callers directly to upstream providers with zero unnecessary hops (see ZAP.md).

   user / api key  ->  hanzoai/gateway  ->  hanzoai/ai (Go)
                                                  |
                              auth: hk-* | JWT | sk-*
                                                  |
                              model routing: 66+ models -> upstream providers
                                                  |
                          +--------+--------+--------+--------+
                          |        |        |        |        |
                       DO-AI  Fireworks  OpenAI   Anthropic   ...
                          |        |        |        |        |
                              KMS-resolved provider secrets
                                                  |
                              IAM usage tracking (async)
Component Role Home
Router Native Go model routing, auth, billing, usage this repo
Frontend Admin UI, chat, knowledge base (React + Ant Design) web/
IAM Identity, API keys (hk-), usage tracking hanzoai/iam
KMS Multi-tenant secrets, org-scoped projects hanzoai/kms
Engine Local inference (Rust) hanzoai/engine
ZAP path
  • /v1 API — JSON over HTTP (/v1/chat/completions, /v1/models)
  • Three auth modes — IAM API key (hk-*), JWT (hanzo.id OAuth), provider key (sk-*)
  • Static model routing — 66+ models mapped to upstream providers in pure Go
  • Per-request usage — async fire-and-forget to IAM
  • KMS-resolved secrets — provider keys from Hanzo KMS, org-scoped
  • RAG — one unified retrieval surface (hybrid keyword + vector) across every tenant index

Supported models

Tier Provider Count Examples
Free DO-AI 28 gpt-4o, gpt-5, o3, qwen3-32b, deepseek-r1-distill-70b, llama-3.3-70b
Premium Fireworks 17 fireworks/deepseek-r1, fireworks/kimi-k2, fireworks/qwen3-coder-480b
Premium OpenAI Direct 5 openai-direct/gpt-5, openai-direct/o3, openai-direct/gpt-4o-mini
Premium (Zen) Hanzo 8 zen4-mini, zen4-pro, zen4-max, zen4-ultra, zen4-coder-pro, zen-vl, zen3-omni

Zen models are Hanzo's own family — owned_by: hanzo, premium. Full list: GET /v1/models (requires a valid Bearer token).

Auto-routing (auto / zen-router)

Opt-in virtual model that picks the best concrete model per request. Send "model": "auto" (alias "zen-router") and the request is classified into a coarse task (code, reasoning, math, creative, vision, long-context, cheap-chat, general) and mapped to the first servable model in the matching preference list — before provider, pricing, and billing resolution. So an auto request is billed and reported as exactly the model that served it.

Enable it in conf/models.yaml (the cloud-api-models ConfigMap in prod), or via env ROUTER_ENABLED=true / ROUTER_ENDPOINT=<url>:

router:
  enabled: true
  endpoint: ""          # optional zen-router URL (see below); "" = built-in heuristic
  cost_ceiling: 0.0
  prefer:
    code:       [zen4-coder, zen5-coder, qwen3-coder, gpt-5.3-codex]
    reasoning:  [zen4-thinking, deepseek-reasoner, zen4-ultra]
    cheap_chat: [zen4-mini, zen5-mini, gpt-4o-mini]
    default:    [zen4, zen5, gpt-4o]
curl -H "Authorization: Bearer hk-YOUR-API-KEY" \
  -H "X-Max-Cost: 2.0" -H "X-Max-Latency-Ms: 800" \
  https://api.hanzo.ai/v1/chat/completions \
  -d '{"model":"auto","messages":[{"role":"user","content":"refactor this function"}]}'
# -> response header:  X-Routed-Model: zen4-coder
# -> response body:    {"model":"zen4-coder", ...}
Per-org enable/disable

Routing can be overridden per org via the admin OrgSettings surface (/v1/*-org-settings, global-admin-gated like /v1/*-model-route). An org row carries autoRouting: "" (unset), "enabled", or "disabled". It blends with the global router.enabled flag as follows (AutoRoutingActive):

global router.enabled org "" (unset) org "enabled" org "disabled"
true route route off (no rewrite, no header)
false off route¹ off

¹ Per-org opt-in routes even when the global flag is off, but ONLY when router config is present (a prefer table or an endpoint) — otherwise there is nothing to route with and auto is left unchanged.

  • Transparency — the X-Routed-Model response header (and the model field in the body) report the model that served the request.
  • SLO (optional) — X-Max-Cost (per-1k, float) and X-Max-Latency-Ms (int) headers express a per-request budget, forwarded to the engine strategy.
  • Two strategies — with endpoint set, ai POSTs {prompt, tasks?, slo} to {endpoint}/route and uses its {model, task, confidence} reply — a learned zen-router (huggingface.co/zenlm/zen-router) served over /v1 by hanzo-engine. On any error (or with no endpoint) it falls back to a built-in pure-Go heuristic, so auto works with zero extra infrastructure. The learned zen-router is the quality upgrade over the heuristic — same interface, better routing.

Configuration

Set via conf/app.conf or environment variables:

Variable Description
HANZO_API_KEY Unified service token for internal IAM + KMS operations (billing/usage/auth)
iamEndpoint IAM service URL (prod: http://iam.hanzo.svc.cluster.local:8000)
clientId / clientSecret IAM OAuth client credentials for ai
dataSourceName Database DSN (do not commit; inject via KMS-managed secret)
KMS_CLIENT_ID / KMS_CLIENT_SECRET KMS Universal Auth credentials
KMS_PROJECT_ID Default KMS project ID
KMS_ENVIRONMENT KMS environment (default: production)

Deploy

# Kubernetes (production)
kubectl apply -f k8s/kms-secrets.yaml
kubectl apply -f k8s/configmap.yaml
kubectl apply -f k8s/deployment.yaml
kubectl apply -f k8s/service.yaml

The production deploy workflow (.github/workflows) resolves credentials from Hanzo KMS. Preferred setup is a single GitHub secret, HANZO_API_KEY; Universal Auth (KMS_CLIENT_ID + KMS_CLIENT_SECRET) remains a fallback.

Noteai runs single-replica: its balance ledger is an in-pod invariant. Deploy strategy: Recreate with min=max=1 (a boot assertion panics if CLOUD_API_REPLICAS > 1). See LLM.md for the scale-out path.

Development

# Backend
go build -race -ldflags "-extldflags '-static'"   # build
go test -v $(go list ./...) -tags skipCi           # test (requires MySQL)
golangci-lint run                                  # lint

# Frontend (web/)
cd web && yarn install && yarn start               # dev server

More detail for AI agents and contributors lives in LLM.md.

License

Apache-2.0

Hanzo — the Open AI Cloud

Open source · every language · on-chain settlement. hanzo.ai · docs.hanzo.ai

SDKs in every languagePython (flagship) · TypeScript · Go · Rust · C++ · Swift · Kotlin · umbrella

Documentation

Overview

Package ai mounts the Hanzo AI subsystem (LLM control plane, RAG, model hub, MCP management) into the unified cloud binary per HIP-0106.

The legacy entry point at ~/work/hanzo/ai/main.go registers the existing beego ControllerRegister tree. Mount adapts that same ControllerRegister onto a zip.App via zip.AdaptNetHTTP so the routes continue to operate unchanged while running under the canonical zip-driven cloud entry.

All ~309 X-Org-Id call-sites inside controllers/* continue to read gateway-minted identity headers (X-Org-Id, X-User-Id, X-User-Email) per HIP-0026 — the adapter does not strip headers; zip middleware in the cloud binary already mints them from the JWT before forwarding.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BillingQueue added in v1.785.4

func BillingQueue() *util.BillingQueue

BillingQueue returns the Commerce billing usage queue created by Bootstrap, or nil if none was configured / Bootstrap did not reach it.

func Bootstrap added in v1.785.4

func Bootstrap() error

Bootstrap performs the AI runtime initialization shared by BOTH entrypoints — the standalone server (cmd/aid) and the embedded unified cloud binary (Mount, per HIP-0106). It is the SINGLE source of the runtime boot sequence: DB + adapter + tables, model/pricing config, the HTTP client, GeoIP/parser, the background maintenance tasks, the Commerce-backed balance gate + tier cache + per-key rate limiter, the full BeforeRouter/AfterExec filter chain, the session config, and the billing usage queue. After wiring those it publishes the fully-configured native router via SetHandler so the unified binary's /v1/ai/* adapter stops returning 503 "ai runtime not initialized".

What Bootstrap deliberately does NOT do (those are standalone-only concerns that the embedded binary owns differently, and several would break or collide when co-resident in the unified process):

  • It binds NO listeners. The native ZAP inference node (port 9999), the inter-service ZAP transport (CLOUD_ZAP_PORT, default 9320) and the standalone HTTP listener (:httpport) stay in cmd/aid. The unified binary serves routers.App through zip on its own :8080 and runs its own ZAP at :9653; starting the legacy nodes here would collide.
  • It calls NO util.StopOldInstance — that races on the legacy standalone port and is meaningless when the embedded binary never listens there.
  • It installs NO signal handler and never calls os.Exit. cloud.Serve owns graceful shutdown for the unified binary; cmd/aid keeps its own drain goroutine, wired to the handles returned here.

Bootstrap is guarded by sync.Once: it is safe to call more than once, so Mount can call it at mount time and the standalone can call it explicitly without double-initializing global runtime state. The cached result (including the error) is returned on every call.

It returns an error rather than panicking: several init steps (notably the DB open) panic deep inside on a missing/unreachable backend, which would take down the whole multi-subsystem cloud binary. Bootstrap recovers those into a precise error so Mount can surface "mount ai: bootstrap: ..." and the operator sees exactly what failed.

The rate limiter and billing queue created here are exposed via RateLimiter() and BillingQueue() for the standalone's graceful-drain wiring. Either may be nil (e.g. the billing queue is nil when no Commerce endpoint is configured).

func Mount

func Mount(app *zip.App, deps cloud.Deps) error

Mount registers AI's HTTP surface per HIP-0106 AND initializes the AI runtime so those routes actually serve.

Routes under /v1/ai/* are forwarded to the registered handler (the beego ControllerRegister built by routers/router.go). The MountSpec contract (cloud.MountAll) gives each subsystem exactly one hook — Mount — and it owns BOTH route wiring and runtime initialization. So Mount calls Bootstrap(), the single shared boot sequence (DB, model config, balance/tier/rate-limit, beego filters, billing queue) that ends by publishing the handler via SetHandler. Without that call the adapter's getHandler() stays nil and every /v1/ai/* request 503s with "ai runtime not initialized" — the exact defect this fixes.

The same Bootstrap() runs in the standalone cmd/aid entrypoint, so the runtime is defined ONCE and behaves identically embedded or standalone. Bootstrap is sync.Once-guarded, so calling it here is safe even if the process also calls it elsewhere.

func RateLimiter added in v1.785.4

func RateLimiter() *routers.RateLimiter

RateLimiter returns the per-key rate limiter created by Bootstrap, or nil if Bootstrap has not run (or failed before creating it).

func SetHandler

func SetHandler(h http.Handler)

SetHandler registers the ai runtime's public HTTP handler (typically beego.BeeApp.Handlers after routers/router.go init). Safe for concurrent use; pass nil to deactivate.

Types

This section is empty.

Directories

Path Synopsis
cmd
aid command
check_ddl command
openapi command
Command openapi renders the resource surface into the canonical spec.
Command openapi renders the resource surface into the canonical spec.
pg2sqlite command
Command pg2sqlite migrates cloud-api's dbx-managed Postgres database to a SQLite file.
Command pg2sqlite migrates cloud-api's dbx-managed Postgres database to a SQLite file.
routerdoc command
Command routerdoc lifts each hand-written route's sentence out of the Go doc comment on the handler it names, into routers/wired_gen.go.
Command routerdoc lifts each hand-written route's sentence out of the Go doc comment on the handler it names, into routers/wired_gen.go.
Package funding is the cash circuit-breaker.
Package funding is the cash circuit-breaker.
internal
gemini
Package gemini is the ONE client for Google's Gemini API, covering exactly the four calls this module makes: countTokens, generateContent, batchEmbedContents and models.list.
Package gemini is the ONE client for Google's Gemini API, covering exactly the four calls this module makes: countTokens, generateContent, batchEmbedContents and models.list.
iam
Package iam is ai's INTERNAL IAM client: the small, clean OIDC+REST surface ai needs to talk to Hanzo IAM (hanzo.id), decoupled from the retired SDK module github.com/hanzoai/iam-v1.
Package iam is ai's INTERNAL IAM client: the small, clean OIDC+REST surface ai needs to talk to Hanzo IAM (hanzo.id), decoupled from the retired SDK module github.com/hanzoai/iam-v1.
Package log is the leveled logging surface for the ai runtime.
Package log is the leveled logging surface for the ai runtime.
Package router turns a chat request into a concrete model id.
Package router turns a chat request into a concrete model id.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL