ai

package module
v1.832.9 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

ai is the AI subsystem of the Hanzo cloud: it serves the /v1 inference surface, routes each request to a model, meters it, and carries the RAG and model-hub surfaces alongside. Pure Go.

Release License

It used to be the whole hanzoai/cloud repository. When the unified binary took the cloud name (HIP-0106), this became ai and now mounts as the ai subsystem inside it. That is why the root of this repository is package ai, a library, and not a main.

Call it

The hosted instance is api.hanzo.ai. Get a key at hanzo.ai:

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

Three auth modes are accepted: an IAM API key (hk-*), a JWT from hanzo.id OAuth, or your own provider key (sk-*), in which case the request is routed with your account rather than metered on ours.

Run it yourself

docker run -p 8000:8000 ghcr.io/hanzoai/ai:vX.Y.Z    # pin a release, never :latest

Or build the server binary. It is cmd/aid — building the repository root gives you a library archive, not something you can run:

CGO_ENABLED=0 go build -o aid ./cmd/aid
./aid -h

compose.yml brings up the server with its Postgres.

Models

The gateway owns the catalog; this service does not keep a second list. Ask it:

curl -H "Authorization: Bearer hk-YOUR-API-KEY" https://api.hanzo.ai/v1/models

https://catalog.hanzo.ai/v1/models answers the same question without a key. Zen is our own family — enso, enso-ultra and the zen5 line, owned_by: hanzo. Models you connect with your own provider keys are routed as well, resolved from Hanzo KMS and scoped to your org.

Auto-routing

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 pricing and billing resolve. So an auto request is billed and reported as exactly the model that served it.

Turn it on in conf/models.yaml (the cloud-api-models ConfigMap in production), or with ROUTER_ENABLED=true / ROUTER_ENDPOINT=<url>:

router:
  enabled: true
  endpoint: ""          # "" = built-in heuristic; a URL = the learned router
  cost_ceiling: 0.0
  prefer:
    code:       [zen5-coder]
    reasoning:  [enso-ultra, enso]
    cheap_chat: [zen5-mini, zen5-flash]
    default:    [zen5]
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: <the model that served it>

X-Routed-Model and the model field in the body always report what actually ran. X-Max-Cost (per 1k, float) and X-Max-Latency-Ms (int) express a per-request budget.

Two strategies sit behind one interface. With endpoint set, ai POSTs {prompt, tasks?, slo} to {endpoint}/route and takes its {model, task, confidence} reply — that is the learned router, zenlm/zen-router. On any error, or with no endpoint configured, it falls back to a built-in Go heuristic, so auto works with no extra infrastructure.

Per-org override

Orgs can opt in or out through the admin OrgSettings surface (/v1/*-org-settings, global-admin-gated like /v1/*-model-route). The org row carries autoRouting: "" (unset), "enabled" or "disabled", and blends with the global flag:

global router.enabled org "" 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.

Configuration

conf/app.conf, or environment variables:

Variable Description
HANZO_API_KEY Service token for internal IAM and KMS calls (billing, usage, auth)
iamEndpoint IAM service URL
clientId / clientSecret IAM OAuth client credentials for ai
dataSourceName Database DSN — inject from KMS, never commit it
KMS_CLIENT_ID / KMS_CLIENT_SECRET KMS Universal Auth credentials
KMS_PROJECT_ID Default KMS project
KMS_ENVIRONMENT KMS environment (default production)

Secrets come from Hanzo KMS; the deploy workflow resolves them at run time from a single HANZO_API_KEY GitHub secret, with Universal Auth as the fallback.

ai runs single-replica: its balance ledger is an in-pod invariant. Deploy with strategy: Recreate and min=max=1 — a boot assertion panics if CLOUD_API_REPLICAS > 1. LLM.md has the scale-out path.

Development

go build -race ./...                       # build
go test $(go list ./...) -tags skipCi      # test (needs MySQL)
golangci-lint run                          # lint

cd web && yarn install && yarn start       # the admin UI

LLM.md is the deep reference — architecture, the mount seam into cloud, and the conventions that apply here. ZAP.md covers the transport.

Lineage

Forked from Casibase, Apache-2.0. See NOTICE. The routing, auth, billing and model surfaces are ours; the admin UI and knowledge-base scaffolding started there.

License

Apache-2.0 — see LICENSE.


Hanzo — the open AI cloud. hanzo.ai · docs.hanzo.ai

SDKs: Python · 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