controllers

package
v1.833.292 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2026 License: Apache-2.0 Imports: 90 Imported by: 0

Documentation

Overview

Copyright 2023-2025 Hanzo AI Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

public_chat.go — a completion for someone with no account.

Every fact a caller normally presents is decided here instead, from facts the request cannot state. The visitor holds no credential and is issued none: they are identified by the address the edge observed, they name no model, and the call is recorded against a reserved org that owns no data.

THE CEILING IS THE SWITCH. publicChatDaily is completions per visitor per UTC day and zero — the default — means the lane does not exist. One number, so a deployment cannot arm the lane and forget the bound, which on an unauthenticated inference route is the only mistake that matters. Every other deployment of this binary — every white-label reseller — stays closed until it says otherwise.

IT FAILS CLOSED, AND ALONE. The bound is counted in this process and depends on no other service, because a bound that asks something else a question admits the call whenever the answer does not arrive. The host's allowance is read as well, so a visitor's usage lands in the one counter that reports a free tier, but a lane that admitted on its silence would be unbounded exactly when the host is down.

A DAY IS SPENT ON ANSWERS. Both counts are read on arrival and raised where the call is served, so a visitor pays for what they got and never for a route that was missing, a vendor that hung, or a pod being rolled.

CORS is not decided here. The edge that fronts this binary owns which browser origins may read it, and a second opinion in this file would be a second answer to one question.

public_scribe.go — a transcription for someone with no account.

The mic on our own pages is offered to visitors who have not signed in, and it is held by the rules public_chat.go holds a completion to, for the same reasons:

  • THE CEILING IS THE SWITCH. publicScribeDaily is transcriptions per visitor per UTC day, and zero — the default — means the lane does not exist.
  • IT FAILS CLOSED, AND ALONE. The count is kept in this process and asks no other service, so it holds while anything else is down.
  • A DAY IS SPENT ON ANSWERS. The count is read on arrival and raised only where a transcript comes back.
  • THE VISITOR IS THE ADDRESS THE EDGE OBSERVED (Lanes): an IPv6 visitor is held by their /64 and by their /48 together, the /48 at siteDay times the limit.

And two rules of its own. The MODEL IS ASSIGNED: publicScribeModel, our own speech service, which pays no vendor — a route that would spend on a vendor closes the lane rather than serving, so nothing a stranger sends reaches the paid lane. And the AUDIO IS HELD TO publicScribeSeconds: the speech service stops decoding just past it and refuses what runs over, so the cap bounds the work. The audio is relayed and dropped; nothing here keeps it or logs what it said.

The growing transcript — /v1/audio/transcriptions' streaming sibling.

POST   /v1/audio/transcript        {model, language}  -> {id, chunk_ms, …}
POST   /v1/audio/transcript/{tid}  <raw pcm16>        -> {text, pending, seconds}
DELETE /v1/audio/transcript/{tid}                     -> the settled text

HTTP-SHAPED, not body-only, and it has to be: the session id is in the PATH (there is no room for it in a body that is raw audio), and push and close share that path and differ only by method. registerGatewayPath hands a handler the body and nothing else, so a body-only registration cannot see either.

TWO THINGS THIS FILE OWNS, and they are the reasons it exists rather than the gateway simply forwarding:

  1. WHICH PROCESS HOLDS THE SESSION. A growing transcript is a window in one speech replica's memory. speech.hanzo.svc is a ClusterIP, and kube-proxy picks a backend PER CONNECTION — so with two replicas roughly half of a session's pushes reach a pod that has never heard of it and answer 404, and a client with a connection pool sees it intermittently. `open` answers with the address of the pod that took the session ("at"), and every later call for that session goes there. A pod that has gone is a session that has gone, which is honest: the window was only ever in its memory.

  2. WHAT IT COST. Audio is metered in seconds and the ledger lives here, not in speech. The quantity is the DELTA OF `seconds`, the cumulative total the session reports — never the per-push `duration`. Two reasons, and both are about not losing money quietly: a cumulative delta has bounded total error (only the last reading's rounding survives) where a sum of per-push values accumulates every one of them; and if one push's response is lost in flight, the next delta covers the gap, where a sum loses that audio for good.

Index

Constants

View Source
const (
	PoolAvailable = "available" // every account takes free requests
	PoolBusy      = "busy"      // some account is out, or all are and one is back within a minute
	PoolExhausted = "exhausted" // no account takes free requests until Resets
)

The free pool's three states.

View Source
const (
	TunnelClosed          int = -1
	Normal                int = 0
	ConnectionNotFound    int = 800
	NewTunnelError        int = 801
	ForcedDisconnect      int = 802
	NodeNotActive         int = 803
	ParametersError       int = 804
	NodeNotFound          int = 805
	ConnectionUpdateError int = 806
)
View Source
const DefaultFreeTierFlashCeilingPerMillion = 3.00

DefaultFreeTierFlashCeilingPerMillion caps the FREE tier's `auto` routing to the flash pool. It is a BLENDED $/1M bound ((input+output)/2 — the blendedPriceForOrg unit). It sits deliberately ABOVE the synthesized default price (default_pricing 1/4 ⇒ blended 2.50), so a servable model with no explicit price (a zen champion, enso-flash) is treated as flash and never dropped, while EVERY premium model sits far above it (glm-5.2 ~6.3, gpt-5.x ~10, o3 ~25, opus/fable ~45) and is excluded with wide margin — as are the pricey non-premium ids (qwen3-coder ~3.6, kimi ~5, deepseek-reasoner ~5.5). The cheap pool (gpt-4o-mini ~0.38, the gemma/mistral/nemotron/llama pool ~0.1–0.35, deepseek-v3.2 ~0.69) is well within it. The family-tier gate already keeps free callers off the enso ladder above enso-flash; this ceiling is the complementary bound that keeps them off the do-ai premium models (not family SKUs).

View Source
const DefaultRouterQualityBias = 1.0

DefaultRouterQualityBias is the dial applied when an org AND the "*" row both leave it unset. It is 1.0 (max quality) on purpose: at bias ≥ 1 applyRouterQualityBias is INERT, so an org that never touches the dial routes EXACTLY as before (the bandit's quality- leaning pick within the cost ceiling) — the dial is strictly opt-in, never a fleet-wide behavior change. An org dials toward savings by explicitly lowering it.

View Source
const DepthDefault = "default"

DepthDefault is the router.depth key for a request that states no reasoning depth.

View Source
const MaxDecoded int64 = 1 << 26

MaxDecoded bounds what one request body may occupy in this process after it has been DECOMPRESSED, in bytes.

It is a different question from what the socket admits (zip.Config.BodyLimit, set in app.go from the upload bound above): that caps what arrives, this caps what it becomes. A zstd frame's ratio on repetitive input runs to thousands to one, so a body small enough to accept can still ask for more heap than any pod has — and the decoder's own default ceiling is 64 GiB. Stating it is the whole protection.

It lived in the in-house web router, which is gone. Both readers are here.

View Source
const MaxSpeechInput = 4096

MaxSpeechInput bounds the text one synthesis request may carry, in bytes of UTF-8. It is OpenAI's /v1/audio/speech limit, for the same reason.

Synthesis cost is LINEAR in input length and the length is known before any work starts, so unlike transcription this bound is exact: it caps the work, not merely the bytes.

View Source
const MaxTranscribeUpload = 25 << 20

MaxTranscribeUpload bounds the audio one transcription request may carry. It is OpenAI's own /v1/audio/transcriptions limit, so every OpenAI-compatible client already chunks below it and none has to learn a Hanzo-specific number.

It is also the multipart parser's memory bound, deliberately the SAME number: a form that cannot exceed this can never spill a temp file, so the disk never participates in an upload at all and there is one limit to reason about instead of a wire limit and a spill limit that can drift apart.

Size is not the whole bound. Bytes do not determine how much AUDIO they carry — the same 25 MiB is ~13 min of 16 kHz PCM or hours of low-bitrate Opus — so the work a request can buy is bounded by the per-org share of the speech ceiling, not by this. See admitSpeech.

View Source
const MsgTypeCloudOps uint16 = 110

MsgTypeCloudOps is the ZAP message type for inter-service cloud operations.

View Source
const RoutedModelHeader = "X-Routed-Model"

RoutedModelHeader is the transparency header the chat controller sets when a virtual `auto`/`zen-router` request was resolved to a concrete model. Callers read it to see which model actually served (the response body echoes the same id in its `model` field).

View Source
const SourceExplicit = "explicit"

SourceExplicit marks a routing event for a request whose model the CALLER chose (not the virtual `auto`). Recorded so EVERY request — not only auto — is a labeled data point the moment the caller rates it: up/down feedback works for ALL models, and the ledger captures which model was selected for which task.

View Source
const SourceMeanField = "meanfield"

SourceMeanField labels a RoutingEvent whose model the congestion layer chose OFF the base champion — an honest origin tag in the ledger, distinct from engine/heuristic/ explore, set ONLY when the mean-field re-rank actually changed the pick.

Variables

View Source
var FreeOnly = func() bool { return true }

FreeOnly reports whether the paid lane is off. The host sets it to the loaded zen catalog's (zen Zen.Free): off only where the catalog says `paid`. Spending is an opt-in, so unset it is on.

View Source
var UpGrader = websocket.FastHTTPUpgrader{
	ReadBufferSize:  4096,
	WriteBufferSize: 4096,
	CheckOrigin: func(ctx *fasthttp.RequestCtx) bool {
		return true
	},
	Subprotocols: []string{"guacamole"},
}

Functions

func Answers added in v1.833.208

func Answers() map[string]Answer

Answers is the whole table. routers joins it to the route that reaches each handler; nothing else reads it.

func Apps added in v1.833.277

func Apps(c *zip.Ctx) []string

Apps are the registered apps the request's validated token was minted for (its `aud`), empty for an API key or an unvalidated token. A plan covers its consumer apps' requests only, and this is the boundary's own answer to which app asked.

func Canonical added in v1.833.247

func Canonical(model string) (string, bool)

Canonical names the id an alias stands for; ok is false for an id that is not an alias.

An id that names Jev never resolves to Kai: an alias that would send one there is no alias, so the request keeps the id it asked for and meets the route table as that id — and a Jev spelling routes to Jev or to nothing.

func ChatPath added in v1.833.277

func ChatPath(path string) bool

ChatPath reports whether path is a chat endpoint.

func ConvertMessageDataToJSON

func ConvertMessageDataToJSON(data string) ([]byte, error)

func Country added in v1.833.241

func Country(c *zip.Ctx) string

Country is the caller's country as the host in front stated it (address.Country), believed on the same terms as the address: only when the peer is one of our own. Empty when nothing trustworthy stated one. CF-IPCountry is never read: the host removes it, and anywhere else it is whatever the caller wrote.

func Cover added in v1.833.277

func Cover(c *zip.Ctx, g *object.LimitGrant)

Cover marks a request its caller's plan covers.

func DecisionBody added in v1.833.251

func DecisionBody(c *zip.Ctx) ([]byte, error)

DecisionBody reads a decision body as sent, or decoded from its one Content-Encoding, neither past decisionBodyBytes, and leaves the request holding it with no coding.

func DecisionFree added in v1.833.253

func DecisionFree(org string) bool

DecisionFree reports whether a model /v1/decisions serves costs org nothing. The balance gate refuses an empty wallet on it before decoding a body only when none does, so a free decision route stays reachable at $0.

func DecisionPath added in v1.833.251

func DecisionPath(path string) bool

DecisionPath reports whether path is /v1/decisions, whose answers Restate words, spelled any way the router matches it: any case, a trailing slash or not.

func DenyRequest

func DenyRequest(ctx *zip.Ctx)

func DepthRoute added in v1.833.233

func DepthRoute(model string, body []byte) (string, bool)

DepthRoute names the priced SKU a request for model is served at when its caller funds it: the router.depth row for model, read at the request's reasoning depth.

It answers only for a model the family serves at no price, and only with a SKU the family serves at a price and without a grant, so it can lift a free call onto the paid ladder and never the reverse. ok is false for every other request, which then runs as sent.

func FamilyModelGated added in v1.809.2

func FamilyModelGated(model string) bool

FamilyModelGated reports whether a model id is a gated family SKU per discovery. Exported so the balance filter (routers) can ask without knowing the family layout. Access to a gated SKU still requires a grant (familyAccessAllowed), but a gated SKU is PAID like any other model — a grant unlocks access, never free billing.

func FamilyOf added in v1.833.277

func FamilyOf(model string) string

FamilyOf names the Hanzo family that serves model — "enso" or "zen" — or "" for a model that is not a Hanzo SKU. The platform's own name for the free pool is Enso's (freeDoor).

func FilterStoresByHomepage

func FilterStoresByHomepage(stores []*object.Store, user *iam.User) []*object.Store

FilterStoresByHomepage filters stores based on user's Homepage field.

func GetUserByAccessKey added in v1.807.1

func GetUserByAccessKey(accessKey string) (*iam.User, error)

GetUserByAccessKey resolves an sk- IAM API key to its owning user via Hanzo IAM. Exported so the authz filter and the balance gate (package routers) resolve the key path to the same verified principal as the JWT path — ONE credential resolver, one tenant, one billing subject, one IAM transport.

func GetUserName

func GetUserName(user *iam.User) string

func InitAuthConfig

func InitAuthConfig() error

InitAuthConfig establishes the IAM signing cert this process validates every bearer token against, eagerly. It is retained for callers that WANT to resolve up front — a CLI, a test — and returns the failure rather than ending the process.

It is deliberately NOT called from an init(). It was, and the cert was fetched over the network before any subsystem mounted, so a momentary IAM outage was a hard outage of everything in this process with no path back: it panicked, the pod crashlooped, and it did not recover on its own once IAM returned. That shape reached production twice (see object.AuthReady for both).

Resolution now happens on first use and retries, and a request that cannot be authenticated is refused with 503 at the edge rather than served without authentication. The security property is unchanged; only the cost of an IAM blip is — the requests during it, instead of the process.

func InitBillingQueue

func InitBillingQueue() *util.BillingQueue

InitBillingQueue creates the billing queue from app config. Must be called once during startup. Returns the queue so main.go can call Shutdown().

func InitForwardBridge added in v1.785.4

func InitForwardBridge(h http.Handler)

func InitInterserviceZap

func InitInterserviceZap()

InitInterserviceZap starts a dedicated ZAP node for inter-service operations. Separate from the main inference ZAP node (port 9999).

func InitModelConfig

func InitModelConfig(path string) error

InitModelConfig loads the YAML config and optionally starts a background refresh goroutine (when live_mode is true). Returns an error if the file cannot be read or parsed. This is non-fatal — the caller can log and fall back to static maps.

func InitZapHandlers

func InitZapHandlers(router http.Handler)

InitZapHandlers registers native ZAP service handlers on the node. router is the fully-wrapped native router (routers.App) that serves every MsgType 200 path the fast-path switch and the registry do not claim.

The router is an ARGUMENT, not a later setter call, because the two are not separable: a gateway handler registered without a router answers 404 to the entire RESTful surface — silently, with the handler present and the node healthy. As a parameter the broken pairing is not expressible; the only way to reach that mode is to write nil, in one visible place.

func IsAutoModel added in v1.833.237

func IsAutoModel(model string) bool

IsAutoModel reports whether a model id is the virtual `auto`/`zen-router` model.

func JudgeMisses added in v1.833.13

func JudgeMisses() uint64

JudgeMisses is the number of judge scoring calls that failed since boot. Read it beside rewarded_events: a count that climbs while rewards stay flat means the judge is BROKEN, not merely sampling — the signal that a silently abstaining judge starved the trainer of the rewards its gate needs.

func KeysURL added in v1.833.221

func KeysURL(host string) string

KeysURL is where a holder mints a key: the API-keys page on the console of the brand host belongs to, "" for a brand that runs none. It is spelled ONCE because every refusal below names it and three copies of an address drift the moment the page moves. It moved already: these messages sent people to cloud.hanzo.ai/keys, which answers 404 (cloud.hanzo.ai is the product site; the console is its own host, and its key surface is /api-keys). A refusal that names a cure the holder cannot reach is worse than one that names none. The key refusals below hold no request and pass "", the default brand.

func Lanes added in v1.833.279

func Lanes(c *zip.Ctx) []address.Bucket

Lanes are every count the caller Visitor names is charged to, narrowest first: a digest of each of the address's buckets, so an IPv6 visitor is held by their /64 and by their /48 together. None when the request carries no public caller.

func ModelCostsNothing added in v1.833.49

func ModelCostsNothing(model, orgId string) bool

ModelCostsNothing is costsNothing for the router's balance filter, which runs BEFORE any controller and therefore before the in-controller gate. Exported for the same reason FamilyModelGated is: the filter must be able to ask what a model costs without knowing how families and price tables are laid out.

func PublishableOrg added in v1.833.103

func PublishableOrg(accessKey string) (string, error)

PublishableOrg resolves a publishable pk- to the org that holds it. Exported so the router's tenant resolver answers a page key the same way the controller does — ONE credential resolver, one tenant, one IAM transport, exactly as GetUserByAccessKey is exported for the secret half.

func QueryCarrierText

func QueryCarrierText(question string, writer *RefinedWriter, history []*model.RawMessage, prompt string, knowledge []*model.RawMessage, modelProviderObj model.ModelProvider, needTitle bool, suggestionCount int, lang string) (*model.ModelResult, error)

func Refusing added in v1.833.251

func Refusing(err error, rid string) (int, []byte, map[string]string)

Refusing is /v1/decisions' answer to an error a layer RETURNED rather than wrote — a refusal the framework raised reading the request included: its status and sentence in the service's shape, a body over the limit as request_too_long, and anything that chose no status as a 500 that says nothing of what failed.

func RequestID added in v1.833.251

func RequestID(inbound string) string

RequestID is the id a decision answers under: the caller's own, when it is one a header can carry back, else a fresh one.

func Restate added in v1.833.251

func Restate(status int, body []byte, header map[string]string, rid string) (_ []byte, changed bool)

Restate is how /v1/decisions says an answer, whoever wrote it: a refusal in the service's error shape, {"error":{"code","message"}}, a 402, 429 or 529 in both Retry-After and Retry-After-Ms, and every answer under X-Request-Id, rid when nobody set one. header holds the answer's headers by canonical name and is completed in place; changed reports whether body was reworded.

func SeedInternalTrainingConsent added in v1.826.4

func SeedInternalTrainingConsent()

SeedInternalTrainingConsent sets TrainingContribution=enabled on the OrgSettings row of every reserved INTERNAL org (reservedInternalOrgs) — our own admin/dev orgs — so their turns are EXPLICITLY opted in. This matters because the per-request EU/EEA/UK judge guard requires EXPLICIT consent (not the opt-out default), so our own traffic stays unambiguously contributable everywhere. Idempotent: an org already "enabled" is left untouched; a missing row is created, any other row is updated in place (preserving its other settings). It ONLY ever touches OUR reserved orgs — it NEVER bulk-enables customer orgs. Best-effort at boot: a per-org failure logs and never blocks startup.

func SetRunResolver added in v1.832.41

func SetRunResolver(f func(token string) (Run, bool))

SetRunResolver installs the lookup that resolves a run key. Called once at startup by the process that owns run lifetimes; passing nil removes it, and then no run key resolves.

This is the same seam shape model.SetContextWindowResolver uses, for the same reason: this package states WHAT it needs to know without importing where the answer lives, so the orchestrator depends on the inference package and never the reverse.

func SettleBudget added in v1.833.251

func SettleBudget() time.Duration

SettleBudget is how long a stopping process must give Settled: every try of a debit at its full timeout, and the waits between them.

func Settled added in v1.833.251

func Settled(ctx context.Context) error

Settled waits until every debit filed after its reply has been handed to the ledger, or ctx ends. A stopping process calls it once it has stopped taking requests, with at least SettleBudget.

func StartRouterJudge added in v1.826.1

func StartRouterJudge()

StartRouterJudge arms the LLM-as-a-judge reward path from DYNAMIC, DB-backed config — no env, no restart. Called once at boot (Bootstrap, next to StartRouterProbe/StartRouterTrainer). It loads the config ONCE synchronously (so the judge is armed before the server serves) then refreshes it on a ticker; admin.hanzo.ai edits to the "*" row take effect within one refresh window. ON by default (object.GetCachedJudgeConfig's built-in defaults run the diverse panel on ~10% of eligible traffic); an admin disables or retunes it live. Never fails boot.

func StartRouterProbe added in v1.815.0

func StartRouterProbe()

StartRouterProbe launches the background self-probe loop when configured. Called once at boot (cmd/aid). Never fails boot: misconfiguration logs and disables. The loop jitters ±20% so probes never synchronize across replicas.

func StartRouterTrainer added in v1.816.0

func StartRouterTrainer()

StartRouterTrainer schedules the fit→gate→deploy→publish loop when enabled. Called once at boot (cmd/aid). Never fails boot.

func StartRoutingConvergence added in v1.833.272

func StartRoutingConvergence()

StartRoutingConvergence applies each family's newest version wherever the family serves something else — after a restart, or an edit made around this surface.

func StopInterserviceZap

func StopInterserviceZap()

StopInterserviceZap gracefully shuts down the inter-service ZAP node.

func Takes added in v1.833.221

func Takes() map[string]any

What each hand-written handler reads.

answers.go is what a handler writes back; this is the body it decodes. Without it the model calls reached the published document with a response and no request, so every generated client's completion method took no body and a first call through an SDK had nowhere to put the model or the messages.

A handler absent from the table reads no JSON body of one fixed shape.

func TraceServedUsage added in v1.814.0

func TraceServedUsage(ctx context.Context, in ServedUsage)

TraceServedUsage emits the warehouse row (hanzo.cloud_usage) + gen_ai span for a self-billed request — recordTrace WITHOUT recordUsage, so the commerce debit the caller already made is never doubled. One warehouse writer, two billers, zero double-billing. Safe under a nil/zero input: an empty Owner still writes an (unattributed) row so traffic is never silently invisible; StartTime zero anchors at now.

func Visitor added in v1.833.106

func Visitor(c *zip.Ctx) string

Visitor is who a caller this estate cannot name is, and the composition is the whole of it: the address, then a digest of it. Empty when the request carries no public caller — a peer of ours that the host did not stamp with one.

It is exported because the router's ceilings ask the same question this lane does. Two derivations of "who is this, roughly" would be two answers a caller could be on either side of: bounded here, unbounded there, and one of them wrong.

func VoiceHandler added in v1.833.96

func VoiceHandler() http.Handler

VoiceHandler serves /v1/voice, or nil when there is no IAM to check a bearer against.

Nil rather than an ungated socket: a WebSocket is exempt from the same-origin policy, so an unauthenticated one is any page on the internet opening a microphone session as whoever is signed in. Absent a gate the right surface is no surface, and the router simply answers 404 as it did before.

func WarmFamilies added in v1.833.237

func WarmFamilies()

WarmFamilies reads every family's catalog once, in the background, so a pod that has just started prices family SKUs from discovery on its first request, and starts reading the balance of every account a family spends.

func WithModel added in v1.833.233

func WithModel(body []byte, model string) ([]byte, bool)

WithModel returns a JSON request body naming model in place of the one it named, every other field as sent. ok is false for a body that is not a JSON object.

Types

type Answer added in v1.833.208

type Answer struct {
	Shape any
	Data  bool
	// Refusals are the statuses the handler refuses with, each with the body it
	// carries. A handler that states none refuses with 401 and 403 and says no more.
	Refusals map[int]Refusal
	// Traced says every answer carries X-Request-Id.
	Traced bool
}

Answer is what one handler writes back.

Data distinguishes the surface's two dialects, which is a real difference and not a flag: an operation reached through ResponseOk answers the {status,msg,data} envelope with Shape in the data field, and an OpenAI- or Anthropic-compatible operation answers Shape and nothing around it.

type AnthropicContentBlock

type AnthropicContentBlock struct {
	Type string `json:"type"`
	Text string `json:"text"`
}

AnthropicContentBlock is a content block in the response.

type AnthropicErrorBody

type AnthropicErrorBody struct {
	Type  string `json:"type"`
	Error struct {
		Type    string `json:"type"`
		Message string `json:"message"`
	} `json:"error"`
}

AnthropicErrorBody is the Anthropic error response shape.

type AnthropicMessage

type AnthropicMessage struct {
	Role    string          `json:"role"`
	Content json.RawMessage `json:"content"`
}

AnthropicMessage is a single message in the Anthropic conversation. Content accepts both string ("hello") and array-of-blocks ([{"type":"text","text":"hello"}]) formats per the Anthropic Messages API.

func (*AnthropicMessage) ContentText

func (m *AnthropicMessage) ContentText() string

ContentText returns the message content as a plain string. Handles both string format and array-of-content-blocks format.

type AnthropicRequest

type AnthropicRequest struct {
	Model       string             `json:"model"`
	MaxTokens   int                `json:"max_tokens"`
	System      json.RawMessage    `json:"system,omitempty"`
	Messages    []AnthropicMessage `json:"messages"`
	Tools       []AnthropicTool    `json:"tools,omitempty"`
	ToolChoice  json.RawMessage    `json:"tool_choice,omitempty"`
	Temperature float32            `json:"temperature,omitempty"`
	Stream      bool               `json:"stream"`
	// Thinking is Anthropic extended-thinking config, read by
	// anthropicThinkingToReasoningEffort for the Anthropic→OpenAI translation. A
	// native upstream is sent the caller's own bytes (nativeRequest), never this
	// struct re-marshalled.
	Thinking json.RawMessage `json:"thinking,omitempty"`
}

AnthropicRequest is the Anthropic Messages API request body.

func (*AnthropicRequest) SystemText

func (r *AnthropicRequest) SystemText() string

SystemText returns the system prompt as a plain string. Handles both string format ("You are helpful") and array format ([{"type":"text","text":"You are helpful"}]) used by the Anthropic SDK.

type AnthropicResponse

type AnthropicResponse struct {
	ID         string                  `json:"id"`
	Type       string                  `json:"type"`
	Role       string                  `json:"role"`
	Content    []AnthropicContentBlock `json:"content"`
	Model      string                  `json:"model"`
	StopReason string                  `json:"stop_reason"`
	Usage      AnthropicUsage          `json:"usage"`
}

AnthropicResponse is the non-streaming Messages API response.

type AnthropicTool added in v1.786.0

type AnthropicTool struct {
	Name        string          `json:"name"`
	Description string          `json:"description,omitempty"`
	InputSchema json.RawMessage `json:"input_schema"`
}

AnthropicTool is a tool definition in the Anthropic format.

type AnthropicUsage

type AnthropicUsage struct {
	InputTokens      int `json:"input_tokens"`
	OutputTokens     int `json:"output_tokens"`
	CacheReadTokens  int `json:"cache_read_input_tokens,omitempty"`
	CacheWriteTokens int `json:"cache_creation_input_tokens,omitempty"`
	// CacheWrites splits CacheWriteTokens by how long the entry is kept, which
	// the vendor prices apart.
	CacheWrites *CacheWrites `json:"cache_creation,omitempty"`
	// Iterations is one usage per time the model ran for this answer. Compaction
	// runs it more than once, and the counts above then cover the last run only.
	Iterations []AnthropicUsage `json:"iterations,omitempty"`
}

AnthropicUsage tracks token counts as the Messages API reports them: the two cache counts are beside InputTokens, not inside it. input_tokens is what was read fresh; the cache counts are what was read from the cache and written to it.

type AnthropicWriter

type AnthropicWriter struct {
	*bufio.Writer
	Cleaner    Cleaner
	Buffer     []byte
	MessageBuf []byte
	RequestID  string
	Stream     bool
	StreamSent bool
	Model      string
	// contains filtered or unexported fields
}

AnthropicWriter implements io.Writer, collecting output for non-streaming and emitting SSE events in Anthropic format for streaming.

func (*AnthropicWriter) Close

func (w *AnthropicWriter) Close(promptTokens, completionTokens, totalTokens int) error

Close finalizes the streaming response with stop events.

func (*AnthropicWriter) Flush added in v1.833.111

func (w *AnthropicWriter) Flush()

Flush satisfies http.Flusher.

It has to be written out even though the embedded *bufio.Writer already has a Flush, because that one returns an error and http.Flusher requires a method returning nothing. The promoted method therefore made this type LOOK flushable while failing the interface assertion, and every streaming model adapter begins by asserting exactly that — so /v1/messages answered "writer does not implement http.Flusher" for every request, tools or not, streaming or not, while /v1/chat/completions beside it was fine.

func (*AnthropicWriter) MessageString

func (w *AnthropicWriter) MessageString() string

MessageString returns the full accumulated message text.

func (*AnthropicWriter) Reset added in v1.833.24

func (w *AnthropicWriter) Reset()

Reset discards what a failed attempt accumulated, so the next provider's answer is not served glued to the dead one's half-sentence. Same contract as OpenAIWriter.Reset, and for the same reason: Write appends, and one writer is shared across every failover attempt.

StreamSent and headerSent are NOT cleared. Both record that bytes reached the CLIENT — a fact about the wire that cannot be undone, and the one that forbids the retry this prepares for.

func (*AnthropicWriter) Write

func (w *AnthropicWriter) Write(p []byte) (n int, err error)

Write processes incoming data chunks from the model provider.

type ApiController

type ApiController struct {
	*zip.Ctx
	// contains filtered or unexported fields
}

ApiController is a request. It embeds the zip context, so a handler reads its body, params, query and headers straight from the wire with no second object in between.

Identity is NOT taken from the embedded context. zip's User/IsAdmin/Org read gateway-set X-User-* headers; ai derives the same facts from a principal it verified itself (GetSessionUser, and principalUser -> ParseAndValidateJWT, which checks the signature and the iss/aud policy). The methods below shadow the embedded ones deliberately: a verified principal is not interchangeable with a header.

func (*ApiController) ActivateFile

func (c *ApiController) ActivateFile()

ActivateFile @Title ActivateFile @Tag File API @Description activate file @Param key query string true "The key of the file" @Param filename query string true "The name of the file" @Success 200 {object} controllers.Response The Response object @router /activate-file [post]

func (*ApiController) AddAIConnection added in v1.803.0

func (c *ApiController) AddAIConnection()

AddAIConnection connects (or reconnects) a third-party AI account for the org by sealing the supplied key into KMS and upserting the org's provider row. The raw key is sealed BEFORE the row is built and is never persisted or echoed. @Title AddAIConnection @Tag AI Connections API @Description connect a third-party AI account by API key (sealed into KMS) @Param body body object true "{provider, apiKey}" @Success 200 {object} controllers.aiConnResponse The Response object @router /ai/connections [post]

func (*ApiController) AddApplication

func (c *ApiController) AddApplication()

AddApplication @Title AddApplication @Tag Application API @Description add application @Param body body object.Application true "The details of the application" @Success 200 {object} controllers.Response The Response object @router /add-application [post]

func (*ApiController) AddArticle

func (c *ApiController) AddArticle()

AddArticle @Title AddArticle @Tag Article API @Description add article @Param body body object.Article true "The details of the article" @Success 200 {object} controllers.Response The Response object @router /add-article [post]

func (*ApiController) AddAsset

func (c *ApiController) AddAsset()

AddAsset @Title AddAsset @Tag Asset API @Description add an asset @Param body body object.Asset true "The details of the asset" @Success 200 {object} controllers.Response The Response object @router /add-asset [post]

func (*ApiController) AddChat

func (c *ApiController) AddChat()

AddChat @Title AddChat @Tag Chat API @Description add chat @Param body body object.Chat true "The details of the chat" @Success 200 {object} controllers.Response The Response object @router /add-chat [post]

func (*ApiController) AddConnection

func (c *ApiController) AddConnection()

func (*ApiController) AddFile

func (c *ApiController) AddFile()

AddFile @Title AddFile @Tag File API @Description add file object @Param body body object.File true "The details of the file object" @Success 200 {object} controllers.Response The Response object @router /add-file [post]

func (*ApiController) AddForm

func (c *ApiController) AddForm()

AddForm @Title AddForm @Tag Form API @Description add form @Param body body object.Form true "The details of the form" @Success 200 {object} controllers.Response The Response object @router /add-form [post]

func (*ApiController) AddGraph

func (c *ApiController) AddGraph()

AddGraph @Title AddGraph @Tag Graph API @Description add Graph @Param body body object.Graph true "The details of the Graph" @Success 200 {object} controllers.Response The Response object @router /add-Graph [post]

func (*ApiController) AddMessage

func (c *ApiController) AddMessage()

AddMessage @Title AddMessage @Tag Message API @Description add message @Param body body object.Message true "The details of the message" @Success 200 {object} object.Chat The Response object @router /add-message [post]

func (*ApiController) AddModelRoute

func (c *ApiController) AddModelRoute()

AddModelRoute @Title AddModelRoute @Tag ModelRoute API @Description add a model route @Param body body object.ModelRoute true "The details of the model route" @Success 200 {object} controllers.Response The Response object @router /add-model-route [post]

func (*ApiController) AddNode

func (c *ApiController) AddNode()

AddNode @Title AddNode @Tag Node API @Description add a node @Param body body object.Node true "The details of the node" @Success 200 {object} controllers.Response The Response object @router /add-node [post]

func (*ApiController) AddNodeTunnel

func (c *ApiController) AddNodeTunnel()

AddNodeTunnel @Title AddNodeTunnel @Tag Connection API @Description add node tunnel session @Param nodeId query string true "The id of node" @Success 200 {object} Response @router /add-node-tunnel [get]

func (*ApiController) AddProvider

func (c *ApiController) AddProvider()

AddProvider @Title AddProvider @Tag Provider API @Description add provider @Param body body object.Provider true "The details of the provider" @Success 200 {object} controllers.Response The Response object @router /add-provider [post]

func (*ApiController) AddRecord

func (c *ApiController) AddRecord()

AddRecord @Title AddRecord @Tag Record API @Description add a record @Param body body object.Record true "The details of the record" @Success 200 {object} controllers.Response The Response object @router /add-record [post]

func (*ApiController) AddRecords

func (c *ApiController) AddRecords()

AddRecords @Title AddRecords @Tag Record API @Description add multiple records @Param body body []object.Record true "The details of the records" @Param sync query string false "Set to 'true' or '1' to enable synchronous processing" @Success 200 {object} controllers.Response The Response object @router /add-records [post]

func (*ApiController) AddRoutingReward added in v1.810.0

func (c *ApiController) AddRoutingReward()

AddRoutingReward attaches a per-request outcome reward to the routing decision that served request_id — the enso training loop's quality signal. Org-scoped via the same session-OR-Bearer principal the usage read uses (RequirePrincipal): the reward lands only on the caller's OWN org's event, so a request_id from another org (or unknown) is a 404 — cross-org writes are impossible and unknown ids are indistinguishable from foreign ones. Idempotent: a repeat overwrites. The body carries NO prompt text — only {request_id, reward|rating}.

@Title AddRoutingReward @Tag Router API @Description attach an outcome reward (0..1) or 1..5 rating to a routed request, for enso training @Param body body controllers.routingRewardRequest true "request_id + reward (0..1) or rating (1..5)" @Success 200 {object} controllers.routingRewardResult The Response object @router /add-routing-reward [post]

func (*ApiController) AddScale

func (c *ApiController) AddScale()

AddScale @router /add-scale [post]

func (*ApiController) AddScan

func (c *ApiController) AddScan()

AddScan @Title AddScan @Tag Scan API @Description add a scan @Param body body object.Scan true "The details of the scan" @Success 200 {object} controllers.Response The Response object @router /add-scan [post]

func (*ApiController) AddSession

func (c *ApiController) AddSession()

AddSession @Title AddSession @Tag Session API @Description Add session for one user in one application. If there are other existing sessions, join the session into the list. @Param id query string true "The id(organization/application/user) of session" @Param sessionId query string true "sessionId to be added" @Success 200 {array} string The Response object @router /add-session [post]

func (*ApiController) AddStore

func (c *ApiController) AddStore()

AddStore @Title AddStore @Tag Store API @Description add store @Param body body object.Store true "The details of the store" @Success 200 {object} controllers.Response The Response object @router /add-store [post]

func (*ApiController) AddTask

func (c *ApiController) AddTask()

AddTask @Title AddTask @Tag Task API @Description add task @Param body body object.Task true "The details of the task" @Success 200 {object} controllers.Response The Response object @router /add-task [post]

func (*ApiController) AddTemplate

func (c *ApiController) AddTemplate()

AddTemplate @Title AddTemplate @Tag Template API @Description add template @Param body body object.Template true "The details of the template" @Success 200 {object} controllers.Response The Response object @router /add-template [post]

func (*ApiController) AddTreeFile

func (c *ApiController) AddTreeFile()

AddTreeFile @Title AddTreeFile @Tag Tree File API @Description add tree file @Param store query string true "The store of the file" @Param key query string true "The key of the file" @Param isLeaf query string true "if is leaf" @Param filename query string true "The name of the file" @Success 200 {object} controllers.Response The Response object @router /add-tree-file [post]

func (*ApiController) AddVector

func (c *ApiController) AddVector()

AddVector @Title AddVector @Tag Vector API @Description add vector @Param body body object.Vector true "The details of the vector" @Success 200 {object} controllers.Response The Response object @router /add-vector [post]

func (*ApiController) AddVideo

func (c *ApiController) AddVideo()

AddVideo @Title AddVideo @Tag Video API @Description add video @Param body body object.Video true "The details of the video" @Success 200 {object} controllers.Response The Response object @router /add-video [post]

func (*ApiController) AddWorkflow

func (c *ApiController) AddWorkflow()

AddWorkflow @Title AddWorkflow @Tag Workflow API @Description add workflow @Param body body object.Workflow true "The details of the workflow" @Success 200 {object} controllers.Response The Response object @router /add-workflow [post]

func (*ApiController) AdminGrantModelAccess added in v1.809.2

func (c *ApiController) AdminGrantModelAccess()

AdminGrantModelAccess grants — or records a request for — one org or user's access to a gated model. SuperAdmin only, at platform scope. The body is {owner, user, email?, model, status?}: an empty user grants the whole org, and status defaults to "granted".

func (*ApiController) AdminListModelAccess added in v1.809.2

func (c *ApiController) AdminListModelAccess()

AdminListModelAccess lists the gated-model access rows, filtered to one org by ?owner. SuperAdmin only; without ?owner it returns every org's rows.

func (*ApiController) AnalyzeTask

func (c *ApiController) AnalyzeTask()

AnalyzeTask @Title AnalyzeTask @Tag Task API @Description analyze task document and generate structured report @Param id query string true "The id (owner/name) of the task" @Success 200 {object} object.TaskResult The Response object @router /analyze-task [post]

func (*ApiController) AnthropicCountTokens added in v1.805.12

func (c *ApiController) AnthropicCountTokens()

AnthropicCountTokens implements POST /v1/messages/count_tokens. Claude Code calls it before a request; it returns {"input_tokens": N} for the given model + messages + tools. @Title AnthropicCountTokens @Tag Anthropic Compatible API @Description Anthropic-compatible token counting. @router /messages/count_tokens [post]

func (*ApiController) AnthropicMessages

func (c *ApiController) AnthropicMessages()

AnthropicMessages implements the Anthropic Messages API. @Title AnthropicMessages @Tag Anthropic Compatible API @Description Anthropic compatible messages API. Accepts:

  • IAM API key (sk-...) via x-api-key or Authorization header
  • hanzo.id JWT token via Authorization header
  • Provider API key via Authorization header

@Param body body AnthropicRequest true "The Anthropic messages request" @Success 200 {object} AnthropicResponse @router /messages [post]

func (*ApiController) AudioMedia added in v1.807.0

func (c *ApiController) AudioMedia()

AudioMedia serves the generative audio verbs — /v1/audio/voice (TTS), /music, /foley — that the Zen family serves natively. It resolves the SKU and, for a Zen model, forwards to zen's matching verb billed per call at the discovered price. These verbs are Zen-native; a non-Zen model is rejected.

func (*ApiController) AudioSpeech added in v1.796.6

func (c *ApiController) AudioSpeech()

AudioSpeech is the OpenAI-compatible TTS endpoint (POST /v1/audio/speech). It authenticates the caller, resolves `model` to its TTS provider (the SAME model-route resolution the chat/images/video endpoints use — so a BYO node registered as a TTS provider works transparently), synthesizes the audio, and streams the bytes back. This is the ONE way to synthesize speech: OpenAI-shaped, with no store or message coupling, so a caller needs no chat to speak.

@Title AudioSpeech @Tag Audio API @Description OpenAI-compatible text-to-speech @Param body body controllers.audioSpeechRequest true "speech request" @Success 200 {file} audio "audio bytes" @router /audio/speech [post]

func (*ApiController) AudioTranscript added in v1.833.288

func (c *ApiController) AudioTranscript()

AudioTranscript serves the growing transcript over HTTP: POST opens one, POST to its id pushes raw pcm16 at 16 kHz, and DELETE closes it with the settled text. The one implementation is zapTranscriptHandler below; this binds it to api.hanzo.ai through the in-process gateway bridge, as the router nouns are.

func (*ApiController) AudioTranscriptions added in v1.832.35

func (c *ApiController) AudioTranscriptions()

AudioTranscriptions is the OpenAI-compatible STT endpoint (POST /v1/audio/transcriptions, multipart: file + model [+ language + response_format]). It mirrors AudioSpeech exactly: authenticate the caller, resolve `model` to its STT provider through the SAME model-route resolution (so the in-cluster speech service — or any BYO node registered as an STT provider — works transparently), transcribe, and return the OpenAI body. This is the ONE way to transcribe: OpenAI-shaped, with no store coupling, so a caller needs no chat to be heard.

@Title AudioTranscriptions @Tag Audio API @Description OpenAI-compatible speech-to-text @Param file formData file true "the audio to transcribe" @Param model formData string true "STT model (whisper family)" @Success 200 {object} controllers.transcriptionResponse "transcription" @router /audio/transcriptions [post]

func (*ApiController) AudioTranscriptionsPublic added in v1.833.290

func (c *ApiController) AudioTranscriptionsPublic()

AudioTranscriptionsPublic transcribes up to a minute of audio for a caller with no account, on Hanzo's own transcriber, within a daily allowance per visitor.

@Title AudioTranscriptionsPublic @Tag Audio API @Description Anonymous speech-to-text on Hanzo's own transcriber. No credential is presented and none is issued; the model is assigned and the audio is held to 60 s. @Param file formData file true "the audio to transcribe, at most 60 s" @Param language formData string false "the spoken language, if known" @Success 200 {object} controllers.transcriptionResponse "transcription" @router /audio/transcriptions/public [post]

func (*ApiController) CallbackAIProvider added in v1.805.0

func (c *ApiController) CallbackAIProvider()

CallbackAIProvider completes OAuth: the org is recovered from the SIGNED state (not a header), the code is exchanged for a token, the token is SEALED into KMS (never the row/logs) through the same path as a BYOK key, and the org's provider row is upserted to "connected". The browser is then redirected back to the console with ?ai_connected=<provider> (or ?ai_connect_error=<provider> on failure). Because the org comes from the state THIS server signed, an attacker cannot land their token in a victim org — which is why this endpoint is state-authenticated rather than credential-gated. @Title CallbackAIProvider @Tag AI Connections API @Description OAuth callback that seals the provider token and connects the account @Param provider path string true "provider slug (openai|anthropic|google)" @Success 302 {string} string redirect back to the console @router /ai/connections/:provider/callback [get]

func (*ApiController) CancelFinetuneJob added in v1.806.13

func (c *ApiController) CancelFinetuneJob()

CancelFinetuneJob deletes the TrainJob CR, meters the GPU-hours used so far, and marks the job cancelled. ?id= or ?name=

func (*ApiController) ChatCompletions

func (c *ApiController) ChatCompletions()

ChatCompletions implements the OpenAI-compatible chat completions API @Title ChatCompletions @Tag OpenAI Compatible API @Description OpenAI compatible chat completions API. Accepts:

  • IAM API key (sk-...) — full model routing + billing
  • hanzo.id JWT token — full model routing + billing
  • Provider API key — direct provider access

@Param body body openai.ChatCompletionRequest true "The OpenAI chat request" @Success 200 {object} openai.ChatCompletionResponse @router /chat [post]

func (*ApiController) ChatCompletionsPublic added in v1.833.56

func (c *ApiController) ChatCompletionsPublic()

ChatCompletionsPublic serves one completion to a caller with no account.

@Title ChatCompletionsPublic @Tag OpenAI Compatible API @Description Anonymous completion on the free pool. No credential is presented and none is issued; the model is the platform's free route and cannot be chosen. @Param body body openai.ChatCompletionRequest true "messages; any model field is ignored" @Success 200 {object} openai.ChatCompletionResponse @router /chat/public [post]

func (*ApiController) CheckSignedIn

func (c *ApiController) CheckSignedIn() (string, bool)

func (*ApiController) CommitRecord

func (c *ApiController) CommitRecord()

CommitRecord @Title CommitRecord @Tag Record API @Description commit a record @Param body body object.Record true "The details of the record" @Success 200 {object} controllers.Response The Response object @router /commit-record [post]

func (*ApiController) CommitRecordSecond

func (c *ApiController) CommitRecordSecond()

CommitRecordSecond @Title CommitRecordSecond @Tag Record API @Description commit a record @Param body body object.Record true "The details of the record" @Success 200 {object} controllers.Response The Response object @router /commit-record-second [post]

func (*ApiController) ConnectAIProvider added in v1.805.0

func (c *ApiController) ConnectAIProvider()

ConnectAIProvider begins an OAuth connection for the caller's org: it binds the org into a signed state and sends the caller to the provider's authorize URL. By default it 302-redirects (a top-level browser "connect your login" click); a SPA/BFF that needs to drive the redirect itself passes ?format=json and gets {authorizeUrl} in the standard envelope. The org is the VERIFIED principal, so only the caller's own connection can result. @Title ConnectAIProvider @Tag AI Connections API @Description begin an OAuth connection to a third-party AI account (login manager) @Param provider path string true "provider slug (openai|anthropic|google)" @Success 302 {string} string redirect to the provider authorize URL @router /ai/connections/:provider/authorize [get]

func (*ApiController) CreateFinetuneJob added in v1.806.13

func (c *ApiController) CreateFinetuneJob()

CreateFinetuneJob validates the request, resolves efficient defaults, persists the job, and submits a real TrainJob CR. A submit failure (e.g. no cluster wired) is surfaced honestly: the job is saved with status "failed" + the reason, never faked.

func (*ApiController) Decisions added in v1.833.242

func (c *ApiController) Decisions()

Decisions implements POST /v1/decisions (the Decisions API).

Body: {"model": "kai", "state": "..."|{...}|[...], "questions": {"<name>": {"type": "choice"|"noul"|"score", "instructions": ..., "criteria": ...}}}. model is kai, Kai's versioned id kai-<12 hex of the weights' sha256> — priced as kai and sent as asked — or Jev by OpenRouter's vendor ids, typesafe/jev-1.13 and ~typesafe/jev-latest, which reach Jev itself and bill at Jev's list price. No Jev id is ever answered by Kai: a bare one, such as jev-latest, is an unknown model. model is required; state and questions are required unless the request names a handle, which carries neither. instructions is optional and any JSON. A choice names at least 2 labels and a score at least 1 level, bounded by the token budget rather than a count; questions holds 1 to 100.

observe holds the state under an id, and a later request naming that id as its handle decides over it again. An id is 1 to 128 characters of A-Z, a-z, 0-9, '.', '_' and '-'. A handle belongs to the org that observed it: no other org's request can name it.

Response: {"id","model","provider","answers":{"<name>":{"type",...}}, "usage":{"input_tokens","output_tokens"},"routing","state_hash","latency_ms"}. usage.input_tokens is the billed count — the request's text counted once, the state once and each question's instructions and options once; a decision over a handle bills the state once, when it was observed.

The body may be sent gzip, deflate, br or zstd encoded; decoded, it is bounded as sent.

Refusals are {"error":{"code","message"}}: 400 malformed JSON or unknown model, 401 no valid credential, 402 insufficient balance, 403 a key kind that may not call this (pk-), 415 any other Content-Encoding, 422 an invalid question or handle id, a state beyond the checkpoint's reach (code state_too_long) or a body past 16 MiB (code request_too_long), 429 rate limited or queue full, 502 the service failed, 503 the model is known and not served, 529 overloaded. 402, 429 and 529 carry Retry-After and Retry-After-Ms, and every answer carries X-Request-Id. Billed on the answer's input tokens at the model's price.

func (*ApiController) DeleteAIConnection added in v1.803.0

func (c *ApiController) DeleteAIConnection()

DeleteAIConnection disconnects a third-party AI account: it deactivates the org's row so completion resolution falls back to the global Hanzo account (no BYO), and best-effort tombstones the sealed secret. Idempotent. @Title DeleteAIConnection @Tag AI Connections API @Description disconnect a third-party AI account @Param provider path string true "provider slug" @Success 200 {object} controllers.aiConnResponse The Response object @router /ai/connections/:provider [delete]

func (*ApiController) DeleteAllVectors

func (c *ApiController) DeleteAllVectors()

DeleteAllVectors @Title DeleteAllVectors @Tag Vector API @Description delete all vectors @Success 200 {object} controllers.Response The Response object @router /delete-all-vectors [post]

func (*ApiController) DeleteApplication

func (c *ApiController) DeleteApplication()

DeleteApplication @Title DeleteApplication @Tag Application API @Description delete application @Param body body object.Application true "The details of the application" @Success 200 {object} controllers.Response The Response object @router /delete-application [post]

func (*ApiController) DeleteArticle

func (c *ApiController) DeleteArticle()

DeleteArticle @Title DeleteArticle @Tag Article API @Description delete article @Param body body object.Article true "The details of the article" @Success 200 {object} controllers.Response The Response object @router /delete-article [post]

func (*ApiController) DeleteAsset

func (c *ApiController) DeleteAsset()

DeleteAsset @Title DeleteAsset @Tag Asset API @Description delete an asset @Param body body object.Asset true "The details of the asset" @Success 200 {object} controllers.Response The Response object @router /delete-asset [post]

func (*ApiController) DeleteChat

func (c *ApiController) DeleteChat()

DeleteChat @Title DeleteChat @Tag Chat API @Description delete chat @Param body body object.Chat true "The details of the chat" @Success 200 {object} controllers.Response The Response object @router /delete-chat [post]

func (*ApiController) DeleteConnection

func (c *ApiController) DeleteConnection()

DeleteConnection @Title DeleteConnection @Tag Connection API @Description delete connection @Param id query string true "The id of connection" @Success 200 {object} Response @router /delete-connection [post]

func (*ApiController) DeleteFile

func (c *ApiController) DeleteFile()

DeleteFile @Title DeleteFile @Tag File API @Description delete file object @Param body body object.File true "The details of the file object" @Success 200 {object} controllers.Response The Response object @router /delete-file [post]

func (*ApiController) DeleteForm

func (c *ApiController) DeleteForm()

DeleteForm @Title DeleteForm @Tag Form API @Description delete form @Param body body object.Form true "The details of the form" @Success 200 {object} controllers.Response The Response object @router /delete-form [post]

func (*ApiController) DeleteGraph

func (c *ApiController) DeleteGraph()

DeleteGraph @Title DeleteGraph @Tag Graph API @Description delete Graph @Param body body object.Graph true "The details of the Graph" @Success 200 {object} controllers.Response The Response object @router /delete-Graph [post]

func (*ApiController) DeleteMessage

func (c *ApiController) DeleteMessage()

DeleteMessage @Title DeleteMessage @Tag Message API @Description delete message @Param body body object.Message true "The details of the message" @Success 200 {object} controllers.Response The Response object @router /delete-message [post]

func (*ApiController) DeleteModelRoute

func (c *ApiController) DeleteModelRoute()

DeleteModelRoute @Title DeleteModelRoute @Tag ModelRoute API @Description delete a model route @Param body body object.ModelRoute true "The details of the model route" @Success 200 {object} controllers.Response The Response object @router /delete-model-route [post]

func (*ApiController) DeleteMyRoutingData added in v1.820.0

func (c *ApiController) DeleteMyRoutingData()

DeleteMyRoutingData deletes ALL of the caller's OWN org routing events — the self-scoped right-to-be-forgotten. Org-admin gated and self-scoped (c.GetOrg()), so a caller can only ever delete its own data, never another tenant's. Completes the data-ownership story: content-free ledger + opt-in + self-export + self-delete.

@Title DeleteMyRoutingData @Tag Router API @Description delete all of the caller's own org routing events (right to be forgotten) @router /delete-my-routing-data [post]

func (*ApiController) DeleteNode

func (c *ApiController) DeleteNode()

DeleteNode @Title DeleteNode @Tag Node API @Description delete a node @Param body body object.Node true "The details of the node" @Success 200 {object} controllers.Response The Response object @router /delete-node [post]

func (*ApiController) DeleteProvider

func (c *ApiController) DeleteProvider()

DeleteProvider @Title DeleteProvider @Tag Provider API @Description delete provider @Param body body object.Provider true "The details of the provider" @Success 200 {object} controllers.Response The Response object @router /delete-provider [post]

func (*ApiController) DeleteRecord

func (c *ApiController) DeleteRecord()

DeleteRecord @Title DeleteRecord @Tag Record API @Description delete a record @Param body body object.Record true "The details of the record" @Success 200 {object} controllers.Response The Response object @router /delete-record [post]

func (*ApiController) DeleteScale

func (c *ApiController) DeleteScale()

DeleteScale @router /delete-scale [post]

func (*ApiController) DeleteScan

func (c *ApiController) DeleteScan()

DeleteScan @Title DeleteScan @Tag Scan API @Description delete a scan @Param body body object.Scan true "The details of the scan" @Success 200 {object} controllers.Response The Response object @router /delete-scan [post]

func (*ApiController) DeleteSession

func (c *ApiController) DeleteSession()

DeleteSession @Title DeleteSession @Tag Session API @Description Delete session for one user in one application. @Param id query string true "The id(organization/application/user) of session" @Success 200 {array} string The Response object @router /delete-session [post]

func (*ApiController) DeleteStore

func (c *ApiController) DeleteStore()

DeleteStore @Title DeleteStore @Tag Store API @Description delete store @Param body body object.Store true "The details of the store" @Success 200 {object} controllers.Response The Response object @router /delete-store [post]

func (*ApiController) DeleteTask

func (c *ApiController) DeleteTask()

DeleteTask @Title DeleteTask @Tag Task API @Description delete task @Param body body object.Task true "The details of the task" @Success 200 {object} controllers.Response The Response object @router /delete-task [post]

func (*ApiController) DeleteTemplate

func (c *ApiController) DeleteTemplate()

DeleteTemplate @Title DeleteTemplate @Tag Template API @Description delete template @Param body body object.Template true "The details of the template" @Success 200 {object} controllers.Response The Response object @router /delete-template [post]

func (*ApiController) DeleteTreeFile

func (c *ApiController) DeleteTreeFile()

DeleteTreeFile @Title DeleteTreeFile @Tag Tree File API @Description delete tree file @Param store query string true "The store of the file" @Param key query string true "The key of the file" @Param isLeaf query string true "if is leaf" @Success 200 {object} controllers.Response The Response object @router /delete-tree-file [post]

func (*ApiController) DeleteVector

func (c *ApiController) DeleteVector()

DeleteVector @Title DeleteVector @Tag Vector API @Description delete vector @Param body body object.Vector true "The details of the vector" @Success 200 {object} controllers.Response The Response object @router /delete-vector [post]

func (*ApiController) DeleteVideo

func (c *ApiController) DeleteVideo()

DeleteVideo @Title DeleteVideo @Tag Video API @Description delete video @Param body body object.Video true "The details of the video" @Success 200 {object} controllers.Response The Response object @router /delete-video [post]

func (*ApiController) DeleteWelcomeMessage

func (c *ApiController) DeleteWelcomeMessage()

func (*ApiController) DeleteWorkflow

func (c *ApiController) DeleteWorkflow()

DeleteWorkflow @Title DeleteWorkflow @Tag Workflow API @Description delete workflow @Param body body object.Workflow true "The details of the workflow" @Success 200 {object} controllers.Response The Response object @router /delete-workflow [post]

func (*ApiController) DeployApplication

func (c *ApiController) DeployApplication()

DeployApplication @Title DeployApplication @Tag Application API @Description deploy application synchronously @Param body body object.Application true "The details of the application" @Success 200 {object} controllers.Response The Response object @router /deploy-application [post]

func (*ApiController) DeployFinetuneJob added in v1.806.13

func (c *ApiController) DeployFinetuneJob()

DeployFinetuneJob serves a completed job's checkpoints and registers the result as a routable model on api.hanzo.ai. ?id= or ?name=

func (*ApiController) Embeddings added in v1.785.10

func (c *ApiController) Embeddings()

Embeddings implements POST /v1/embeddings (OpenAI-compatible).

Body: {"model": "...", "input": "..."|["...", ...], "encoding_format"?, "dimensions"?} It authenticates the caller, resolves the model to its upstream provider via the shared routing table, rewrites the user-facing model name to the upstream id, and proxies the request to the provider's /embeddings endpoint verbatim.

func (*ApiController) EnforceStoreIsolation

func (c *ApiController) EnforceStoreIsolation(requestedStoreName string) (string, bool)

EnforceStoreIsolation applies that rule and refuses on the request.

func (*ApiController) ExportMyRoutingData added in v1.820.0

func (c *ApiController) ExportMyRoutingData()

ExportMyRoutingData streams the CALLER'S OWN org routing events as JSONL. Org- admin gated and SELF-SCOPED — the org is forced to c.GetOrg(), never a query or body value — so a customer exports only its own content-free ledger. This is the customer-facing data-ownership read that pairs with the training opt-in; the super-admin, any-org ExportRoutingLedger above is the platform operator's export.

@Title ExportMyRoutingData @Tag Router API @Description export the caller's own org routing events (content-free) as JSONL @router /export-my-routing-data [get]

func (*ApiController) Finish

func (c *ApiController) Finish()

func (*ApiController) GetAIConnectionUsage added in v1.809.0

func (c *ApiController) GetAIConnectionUsage()

GetAIConnectionUsage imports the caller org's usage for a connected third-party account. The org is resolved from the VERIFIED principal (requireConnectionOrg), so a tenant reads only its own connection. The key is unsealed SERVER-SIDE and never returned. An unconnected account, a missing importer, or a scope-denied provider all return a 200 ProviderUsage with connected/available flags + a human note — the UI's honest-empty states — never a fabricated figure. @Title GetAIConnectionUsage @Tag AI Connections API @Description import a connected third-party AI account's usage (spend/tokens/requests/per-model/series) @Param provider path string true "provider slug (see GET /v1/ai/connections)" @Param from query string false "window start (RFC3339, YYYY-MM-DD, or unix seconds; default 30d ago)" @Param to query string false "window end (RFC3339, YYYY-MM-DD, or unix seconds; default now)" @Success 200 {object} controllers.ProviderUsage The Response object @router /ai/connections/:provider/usage [get]

func (*ApiController) GetAIConnections added in v1.803.0

func (c *ApiController) GetAIConnections()

GetAIConnections lists the org's connectable AI accounts and whether each is currently connected. Never returns a key or a kms:// reference. @Title GetAIConnections @Tag AI Connections API @Description list the org's connected third-party AI accounts (login manager) @Success 200 {array} controllers.aiConnResponse The Response object @router /ai/connections [get]

func (*ApiController) GetAcceptLanguage

func (c *ApiController) GetAcceptLanguage() string

func (*ApiController) GetAccount

func (c *ApiController) GetAccount()

GetAccount @Title GetAccount @Tag Account API @Description get account @Success 200 {object} iam.Claims The Response object @router /get-account [get]

func (*ApiController) GetActiveFile

func (c *ApiController) GetActiveFile()

GetActiveFile @Title GetActiveFile @Tag File API @Description get active file @Param prefix query string true "The prefix of the file" @Success 200 {string} string "get active file" @router /get-active-file [get]

func (*ApiController) GetActivities

func (c *ApiController) GetActivities()

GetActivities @Title GetActivities @Tag Activity API @Description get activities @Param days query string true "days count" @Success 200 {array} object.Activity The Response object @router /get-activities [get]

func (*ApiController) GetAdminProviders added in v1.790.5

func (c *ApiController) GetAdminProviders()

GetAdminProviders @Title GetAdminProviders @Tag Provider Admin API @Description List admin-owned Model providers as a clean management view

(enabled/primary/keyPresent/modelCount). Never returns secret material.
Super-admin gated (see routers/authz_filter.go superAdminEndpoints).

@Success 200 {array} controllers.adminProviderView The Response object @router /admin/providers [get]

func (*ApiController) GetAgentsDashboardUrl

func (c *ApiController) GetAgentsDashboardUrl()

GetAgentsDashboardUrl returns the URL of the Hanzo Agents control plane dashboard.

@Title GetAgentsDashboardUrl @Tag Agents API @Description get agents dashboard URL @Success 200 {object} Response The Response object @router /get-agents-dashboard-url [get]

func (*ApiController) GetAnswer

func (c *ApiController) GetAnswer()

GetAnswer @Title GetAnswer @Tag Message API @Description get answer @Param provider query string true "The provider" @Param question query string true "The question of message" @Param framework query string true "The framework" @Param video query string true "The video" @Success 200 {string} string "answer message" @router /get-answer [get]

func (*ApiController) GetApplication

func (c *ApiController) GetApplication()

func (*ApiController) GetApplications

func (c *ApiController) GetApplications()

GetApplications @Title GetApplications @Tag Application API @Description get applications @Param owner query string true "The owner of applications" @Success 200 {array} object.Application The Response object @router /get-applications [get]

func (*ApiController) GetArticle

func (c *ApiController) GetArticle()

GetArticle @Title GetArticle @Tag Article API @Description get article @Param id query string true "The id (owner/name) of article" @Success 200 {object} object.Article The Response object @router /get-article [get]

func (*ApiController) GetArticles

func (c *ApiController) GetArticles()

GetArticles @Title GetArticles @Tag Article API @Description get articles @Param owner query string true "The owner of article" @Success 200 {array} object.Article The Response object @router /get-articles [get]

func (*ApiController) GetAsset

func (c *ApiController) GetAsset()

GetAsset @Title GetAsset @Tag Asset API @Description get asset @Param id query string true "The id ( owner/name ) of the asset" @Success 200 {object} object.Asset The Response object @router /get-asset [get]

func (*ApiController) GetAssets

func (c *ApiController) GetAssets()

GetAssets @Title GetAssets @Tag Asset API @Description get all assets @Param pageSize query string false "The size of each page" @Param p query string false "The number of the page" @Success 200 {object} object.Asset The Response object @router /get-assets [get]

func (*ApiController) GetChat

func (c *ApiController) GetChat()

GetChat @Title GetChat @Tag Chat API @Description get chat @Param id query string true "The id of chat" @Success 200 {object} object.Chat The Response object @router /get-chat [get]

func (*ApiController) GetChats

func (c *ApiController) GetChats()

GetChats @Title GetChats @Tag Chat API @Description get chats @Param user query string true "The user of chat" @Param field query string true "The field of chat" @Param value query string true "The value of chat" @Param startTime query string false "Filter by start time" @Param endTime query string false "Filter by end time" @Success 200 {array} object.Chat The Response object @router /get-chats [get]

func (*ApiController) GetCloudUsages added in v1.786.0

func (c *ApiController) GetCloudUsages()

GetCloudUsages @Title GetCloudUsages @Tag Usage API @Description Overview aggregation of the hanzo.cloud_usage ledger: totals + prior-period deltas, an evenly-spaced time series, spend-by-model (top-N + other), and the recent-activity feed, for a time range. @Param range query string false "24h | 7d | 30d | custom (default 24h)" @Param start query string false "custom range start (RFC3339 or unix seconds)" @Param end query string false "custom range end (RFC3339 or unix seconds)" @Param org query string false "super admin only: target org slug, 'all' for every org" @Param topModels query string false "spend-by-model top-N (default 6)" @Param activityType query string false "all | inference (default all)" @Param activityLimit query string false "recent-activity page size (default 20)" @Param activityOffset query string false "recent-activity page offset (default 0)" @Success 200 {object} object.CloudUsageOverview The Response object @router /get-cloud-usages [get]

Auth is session-OR-Bearer (c.RequirePrincipal): the console sends a session cookie, while the token-bearing surfaces (app / chat / billing, which drive the unified UsagePanel) send an IAM Bearer. Both resolve to the SAME principal, and the scope below is decided from THAT principal alone.

Scoping is the dual-use o11y read shared by tenant surfaces (own-org) and admin.hanzo.ai (god-view): a non-super-admin is pinned to their own org — request scope hints (X-Org-Id header, ?org=) are ignored, so a tenant can never read another org, no matter which auth it presents. A super admin targets one org via ?org=<slug> (or the X-Org-Id header console2 stamps), or omits it / passes ?org=all for the ALL-orgs view. The super-admin decision comes from the verified principal (util.IsSuperAdmin), never from a header or param.

func (*ApiController) GetConnection

func (c *ApiController) GetConnection()

GetConnection @Title GetConnection @Tag Connection API @Description get connection @Param id query string true "The id of connection" @Success 200 {object} object.Connection @router /get-connection [get]

func (*ApiController) GetConnections

func (c *ApiController) GetConnections()

GetConnections @Title GetConnections @Tag Connection API @Description get all connections @Param pageSize query string true "The size of each page" @Param p query string true "The number of the page" @Success 200 {object} object.Connection The Response object @router /get-connections [get]

func (*ApiController) GetFile added in v1.833.89

GetFile returns one uploaded part by name.

func (*ApiController) GetFileMy

func (c *ApiController) GetFileMy()

GetFileMy @Title GetFileMy @Tag File API @Description get file object @Param id query string true "The id (owner/name) of the file object" @Success 200 {object} object.File The Response object @router /get-file [get]

func (*ApiController) GetFiles

func (c *ApiController) GetFiles()

GetFiles @Title GetFiles @Tag File API @Description get file objects @Param owner query string true "The owner of the file object" @Success 200 {array} object.File The Response object @router /get-files [get]

func (*ApiController) GetFinetuneJob added in v1.806.13

func (c *ApiController) GetFinetuneJob()

GetFinetuneJob returns one job with refreshed live status. ?id=owner/name or ?name=

func (*ApiController) GetFinetunePresets added in v1.806.13

func (c *ApiController) GetFinetunePresets()

GetFinetunePresets returns the new-job catalog plus, when a selection is passed (?baseModel&method&task&preset[&datasetExamples]), the recommended config so the console can render "Recommended" as a one-click, ready-to-run default.

func (*ApiController) GetForm

func (c *ApiController) GetForm()

GetForm @Title GetForm @Tag Form API @Description get form @Param id query string true "The id (owner/name) of form" @Success 200 {object} object.Form The Response object @router /get-form [get]

func (*ApiController) GetFormData

func (c *ApiController) GetFormData()

GetFormData @Title GetFormData @Tag Form API @Description get forms @Param owner query string true "The owner of form" @Success 200 {array} object.Form The Response object @router /get-form-data [get]

func (*ApiController) GetForms

func (c *ApiController) GetForms()

GetForms @Title GetForms @Tag Form API @Description get forms @Param owner query string true "The owner of form" @Success 200 {array} object.Form The Response object @router /get-forms [get]

func (*ApiController) GetGlobalArticles

func (c *ApiController) GetGlobalArticles()

GetGlobalArticles @Title GetGlobalArticles @Tag Article API @Description get global articles @Success 200 {array} object.Article The Response object @router /get-global-articles [get]

func (*ApiController) GetGlobalChats

func (c *ApiController) GetGlobalChats()

GetGlobalChats @Title GetGlobalChats @Tag Chat API @Description get global chats @Success 200 {array} object.Chat The Response object @router /get-global-chats [get]

func (*ApiController) GetGlobalFiles

func (c *ApiController) GetGlobalFiles()

GetGlobalFiles @Title GetGlobalFiles @Tag File API @Description get global file objects @Success 200 {array} object.File The Response object @router /get-global-files [get]

func (*ApiController) GetGlobalForms

func (c *ApiController) GetGlobalForms()

GetGlobalForms @Title GetGlobalForms @Tag Form API @Description get global forms @Success 200 {array} object.Form The Response object @router /get-global-forms [get]

func (*ApiController) GetGlobalGraphs

func (c *ApiController) GetGlobalGraphs()

GetGlobalGraphs @Title GetGlobalGraphs @Tag Graph API @Description get global graphs @Success 200 {array} object.Graph The Response object @router /get-global-graphs [get]

func (*ApiController) GetGlobalProviders

func (c *ApiController) GetGlobalProviders()

GetGlobalProviders @Title GetGlobalProviders @Tag Provider API @Description get global providers @Success 200 {array} object.Provider The Response object @router /get-global-providers [get]

func (*ApiController) GetGlobalScales

func (c *ApiController) GetGlobalScales()

GetGlobalScales @Title GetGlobalScales @Tag Scale API @Success 200 {array} object.Scale The Response object @router /get-global-scales [get]

func (*ApiController) GetGlobalStores

func (c *ApiController) GetGlobalStores()

func (*ApiController) GetGlobalTasks

func (c *ApiController) GetGlobalTasks()

GetGlobalTasks @Title GetGlobalTasks @Tag Task API @Description get global tasks @Success 200 {array} object.Task The Response object @router /get-global-tasks [get]

func (*ApiController) GetGlobalVectors

func (c *ApiController) GetGlobalVectors()

GetGlobalVectors @Title GetGlobalVectors @Tag Vector API @Description get global vectors @Success 200 {array} object.Vector The Response object @router /get-global-vectors [get]

func (*ApiController) GetGlobalVideos

func (c *ApiController) GetGlobalVideos()

GetGlobalVideos @Title GetGlobalVideos @Tag Video API @Description get global videos @Success 200 {array} object.Video The Response object @router /get-global-videos [get]

func (*ApiController) GetGlobalWorkflows

func (c *ApiController) GetGlobalWorkflows()

GetGlobalWorkflows @Title GetGlobalWorkflows @Tag Workflow API @Description get global workflows @Success 200 {array} object.Workflow The Response object @router /get-global-workflows [get]

func (*ApiController) GetGraph

func (c *ApiController) GetGraph()

GetGraph @Title GetGraph @Tag Graph API @Description get Graph @Param id query string true "The id (owner/name) of Graph" @Success 200 {object} object.Graph The Response object @router /get-Graph [get]

func (*ApiController) GetGraphs

func (c *ApiController) GetGraphs()

GetGraphs @Title GetGraphs @Tag Graph API @Description get graphs @Param owner query string true "The owner of Graph" @Success 200 {array} object.Graph The Response object @router /get-graphs [get]

func (*ApiController) GetHfRepo added in v1.806.13

func (c *ApiController) GetHfRepo()

GetHfRepo returns a repo's detail (files, gated/private state). ?id=&kind=model|dataset

func (*ApiController) GetK8sStatus

func (c *ApiController) GetK8sStatus()

GetK8sStatus @Title GetK8sStatus @Tag Deployment API @Description get kubernetes cluster status @Success 200 {object} object.K8sStatus The Response object @router /get-k8s-status [get]

func (*ApiController) GetMessage

func (c *ApiController) GetMessage()

GetMessage @Title GetMessage @Tag Message API @Description get message @Param id query string true "The id of message" @Success 200 {object} object.Message The Response object @router /get-message [get]

func (*ApiController) GetMessageAnswer

func (c *ApiController) GetMessageAnswer()

GetMessageAnswer @Title GetMessageAnswer @Tag Message API @Description get message answer @Param id query string true "The id of message" @Success 200 {stream} string "An event stream of message answers in JSON format" @router /get-message-answer [get]

func (*ApiController) GetMessages

func (c *ApiController) GetMessages()

GetMessages @Title GetMessages @Tag Message API @Description get Messages @Param user query string true "The user of message" @Param chat query string true "The chat of message" @Success 200 {array} object.Message The Response object @router /get-Messages [get]

func (*ApiController) GetMetrics

func (c *ApiController) GetMetrics()

GetMetrics @Title GetMetrics @Tag System API @Description get Prometheus metrics @Success 200 {string} string The Response metrics in Prometheus format @router /metrics [get]

func (*ApiController) GetModelAccessStatus added in v1.809.2

func (c *ApiController) GetModelAccessStatus()

GetModelAccessStatus returns the caller's own standing for a gated model: "granted", "requested", or empty when they have never asked.

func (*ApiController) GetModelProviders added in v1.832.17

func (c *ApiController) GetModelProviders()

GetModelProviders @Title GetModelProviders @Tag Model API @Description Public, secret-free list of the providers serving the models that

GET /v1/models lists — the same source, projected. Safe unauthenticated: no
keys, URLs, or config are returned, and it reports a SET of names, never
which provider serves which model.

@Success 200 {object} controllers.modelProviders The Response object @router /models/providers [get]

func (*ApiController) GetModelRoute

func (c *ApiController) GetModelRoute()

GetModelRoute @Title GetModelRoute @Tag ModelRoute API @Description get a specific model route @Param owner query string true "The owner (org)" @Param modelName query string true "The model name" @Success 200 {object} object.ModelRoute The Response object @router /get-model-route [get]

func (*ApiController) GetModelRoutes

func (c *ApiController) GetModelRoutes()

GetModelRoutes @Title GetModelRoutes @Tag ModelRoute API @Description get model routes for an owner @Param owner query string true "The owner (org) of the model routes" @Success 200 {array} object.ModelRoute The Response object @router /get-model-routes [get]

func (*ApiController) GetNode

func (c *ApiController) GetNode()

GetNode @Title GetNode @Tag Node API @Description get node @Param id query string true "The id ( owner/name ) of the node" @Success 200 {object} object.Node The Response object @router /get-node [get]

func (*ApiController) GetNodeTunnel

func (c *ApiController) GetNodeTunnel()

GetNodeTunnel @Title GetNodeTunnel @Tag Connection API @Description get node tunnel session @Param width query string true "The width of the tunnel" @Param height query string true "The height of the tunnel" @Param dpi query string true "The dpi of the tunnel" @Param connectionId query string true "The id of the connectionId" @Param username query string true "The username for the tunnel" @Param password query string true "The password for the tunnel" @Success 200 {object} Response @router /get-node-tunnel [get]

func (*ApiController) GetNodes

func (c *ApiController) GetNodes()

GetNodes @Title GetNodes @Tag Node API @Description get all nodes @Param pageSize query string true "The size of each page" @Param p query string true "The number of the page" @Success 200 {object} object.Node The Response object @router /get-nodes [get]

func (*ApiController) GetOrg added in v1.804.1

func (c *ApiController) GetOrg() string

GetOrg resolves the organization a request ACTS IN — data scoping, routing, pricing, usage reads, record attribution — from the VERIFIED request principal, never a raw client header.

X-Org-Id is honored when it names the principal's own org, an org the SIGNED `orgs` claim says the principal belongs to (the org switcher), or any org at all for a super admin (cross-tenant platform access). A non-member's request is silently answered with its home org: a spoofed header can never widen scope, and the refusal discloses nothing.

This is the SCOPE answer, not the MONEY answer. What a request SPENDS FROM is billingOrg, which differs for exactly one principal — a super admin acting inside a customer tenant scopes to the customer and spends its own ledger.

func (*ApiController) GetPrometheusInfo

func (c *ApiController) GetPrometheusInfo()

GetPrometheusInfo @Title GetPrometheusInfo @Tag System API @Description get Prometheus Info @Success 200 {object} object.PrometheusInfo The Response object @router /get-prometheus-info [get]

func (*ApiController) GetProvider

func (c *ApiController) GetProvider()

GetProvider @Title GetProvider @Tag Provider API @Description get provider @Param id query string true "The id of provider" @Success 200 {object} object.Provider The Response object @router /get-provider [get]

func (*ApiController) GetProviders

func (c *ApiController) GetProviders()

GetProviders @Title GetProviders @Tag Provider API @Description get providers @Success 200 {array} object.Provider The Response object @router /get-providers [get]

func (*ApiController) GetPublicScales

func (c *ApiController) GetPublicScales()

GetPublicScales @Title GetPublicScales @Tag Scale API @Success 200 {array} object.Scale The Response object @router /get-public-scales [get]

func (*ApiController) GetRangeUsages

func (c *ApiController) GetRangeUsages()

GetRangeUsages @Title GetRangeUsages @Tag Usage API @Description get range usages @Param count query string true "count of range usages" @Success 200 {array} object.Usage The Response object @router /get-range-usages [get]

func (*ApiController) GetRecord

func (c *ApiController) GetRecord()

GetRecord @Title GetRecord @Tag Record API @Description get record @Param id query string true "The id ( owner/name ) of the record" @Success 200 {object} object.Record The Response object @router /get-record [get]

func (*ApiController) GetRecords

func (c *ApiController) GetRecords()

GetRecords @Title GetRecords @Tag Record API @Description get all records @Param pageSize query string true "The size of each page" @Param p query string true "The number of the page" @Success 200 {object} object.Record The Response object @router /get-records [get]

func (*ApiController) GetRequestTenantOrgID

func (c *ApiController) GetRequestTenantOrgID() string

func (*ApiController) GetRequestTenantProjectID

func (c *ApiController) GetRequestTenantProjectID() string

func (*ApiController) GetRouterHistory added in v1.818.0

func (c *ApiController) GetRouterHistory()

GetRouterHistory returns the router-improvement time-series. Two scopes, one route, mirroring /v1/ai/router/stats:

  • ?scope=platform — PUBLIC-safe aggregate over ALL orgs, no authentication. Emits the daily reward/cost-saved/adoption series (task mix included, model ids NOT) and the retrain timeline. This is what world.hanzo.ai polls.
  • default (org scope) — requires a signed-in principal, scoped to the caller's OWN org (a super admin may pass ?org= to target another or "" for all).

Window: ?days=N (default 30, capped at 90). Aggregates only.

@Title GetRouterHistory @Tag Router API @Description router improvement time-series (reward + cost-saved + adoption over time, retrain markers); scope=platform is public-safe @Param scope query string false "'platform' for the public aggregate; omit for the caller's org" @Param days query int false "window size in days (default 30, max 90)" @Param org query string false "super-admin only: target org (” = all orgs)" @Success 200 {object} controllers.routerHistory The Response object @router /router/history [get]

func (*ApiController) GetRouterJudgePanel added in v1.826.5

func (c *ApiController) GetRouterJudgePanel()

GetRouterJudgePanel returns the LIVE Mean-Field Judge Panel state: the configured panel + dynamic judge posture (enabled/sample) resolved from the "*" GlobalDefaultOwner row, the live in-process per-judge calibration (weight/mean/n), and the static published benchmark. PUBLIC-safe and platform-global (model ids + scalars only), so it rides the same unauthenticated, balance-exempt class as /v1/ai/router/stats?scope=platform — the world widget polls it with no auth. The judge state is a single in-process population (not per-org), so there is nothing to scope; ?scope=platform is accepted for symmetry with router-stats.

@Title GetRouterJudgePanel @Tag Router API @Description live Mean-Field Judge Panel state (public, platform-global; model ids + scalars only) @Param scope query string false "'platform' (default) — the public panel snapshot" @Success 200 {object} controllers.judgePanelState The Response object @router /router/judge-panel [get]

func (*ApiController) GetRouterStats added in v1.811.0

func (c *ApiController) GetRouterStats()

GetRouterStats returns the router observability aggregate. Two scopes, one route:

  • ?scope=platform — PUBLIC-safe aggregate over ALL orgs, no authentication. Emits rates, shares, per-task/per-model counts, throughput, and the cost RATIO (saved_pct) + counterfactual model id, but NEVER absolute $ levels, org identity, raw events, or feature vectors. This is what world.hanzo.ai polls.
  • default (org scope) — requires a signed-in principal; scoped to the caller's OWN org (a super admin may pass ?org= to target another org or "" for all). Carries the absolute $/MTok indices for the admin savings panel.

Window: ?since= (RFC3339) or ?hours= (default 24, capped). Aggregates only.

@Title GetRouterStats @Tag Router API @Description router savings-vs-performance aggregate (scope=platform is public-safe; default is org-scoped) @Param scope query string false "'platform' for the public aggregate; omit for the caller's org" @Param org query string false "super-admin only: target org (” = all orgs)" @Param hours query int false "window size in hours (default 24)" @Param since query string false "window start (RFC3339); overrides hours" @Success 200 {object} controllers.routerStats The Response object @router /router/stats [get]

func (*ApiController) GetScale

func (c *ApiController) GetScale()

GetScale @router /get-scale [get]

func (*ApiController) GetScales

func (c *ApiController) GetScales()

GetScales @Title GetScales @Tag Scale API @router /get-scales [get]

func (*ApiController) GetScan

func (c *ApiController) GetScan()

GetScan @Title GetScan @Tag Scan API @Description get scan @Param id query string true "The id ( owner/name ) of the scan" @Success 200 {object} object.Scan The Response object @router /get-scan [get]

func (*ApiController) GetScans

func (c *ApiController) GetScans()

GetScans @Title GetScans @Tag Scan API @Description get all scans @Param pageSize query string false "The size of each page" @Param p query string false "The number of the page" @Param asset query string false "Filter by asset name" @Success 200 {object} object.Scan The Response object @router /get-scans [get]

func (*ApiController) GetScopedOwner

func (c *ApiController) GetScopedOwner() (string, bool)

GetScopedOwner resolves owner from the authenticated session. Non-admin users are always scoped to their own org, ignoring request owner params. Super admins can optionally target a specific owner via query parameter.

func (*ApiController) GetSessionClaims

func (c *ApiController) GetSessionClaims() *iam.Claims

Who this request is, and there is one answer.

The credential is the IAM access token: an Authorization bearer, or the first-party cookie a browser sign-in left (setIamTokenCookie). Both carry the SAME signed token, and it is verified here — signature plus the iss/aud policy — so identity is never taken on trust and a missing or unreadable credential grants nothing.

There is no session store behind this. There used to be, and the id it handed the browser was itself a credential: a value an attacker could plant and then have the victim's sign-in authenticate. A signed token cannot be fixated that way — the client cannot choose one that verifies — so rotating an id on the way in is no longer a property to remember, it is a shape the credential does not have. IAM mints and revokes; ai reads.

func (*ApiController) GetSessionOwner

func (c *ApiController) GetSessionOwner() string

GetSessionOwner returns the organization (owner) of the authenticated user. This ensures multi-tenant resource scoping — users only see their own org's resources.

func (*ApiController) GetSessionUser

func (c *ApiController) GetSessionUser() *iam.User

GetSessionUser is the caller, or nil when the request carries no credential this process can verify.

func (*ApiController) GetSessionUsername

func (c *ApiController) GetSessionUsername() string

func (*ApiController) GetSessions

func (c *ApiController) GetSessions()

GetSessions @Title GetSessions @Tag Session API @Description Get organization user sessions. @Param owner query string true "The organization name" @Success 200 {array} string The Response object @router /get-sessions [get]

func (*ApiController) GetSingleSession

func (c *ApiController) GetSingleSession()

GetSingleSession @Title GetSingleSession @Tag Session API @Description Get session for one user in one application. @Param id query string true "The id(organization/user) of session" @Success 200 {array} string The Response object @router /get-session [get]

func (*ApiController) GetStorageProviders

func (c *ApiController) GetStorageProviders()

GetStorageProviders @Title GetStorageProviders @Tag Storage Provider API @Description get storage providers @Success 200 {array} object.Provider The Response object @router /get-storage-providers [get]

func (*ApiController) GetStore

func (c *ApiController) GetStore()

GetStore @Title GetStore @Tag Store API @Description get store @Param id query string true "The id (owner/name) of the store" @Success 200 {object} object.Store The Response object @router /get-store [get]

func (*ApiController) GetStoreNames

func (c *ApiController) GetStoreNames()

GetStoreNames ... @Title GetStoreNames @Tag Store API @Param owner query string true "owner" @Description get all store name and displayName @Success 200 {array} object.Store The Response object @router /get-store-names [get]

func (*ApiController) GetStores

func (c *ApiController) GetStores()

GetStores @Title GetStores @Tag Store API @Description get stores @Param owner query string true "The owner of the store" @Success 200 {array} object.Store The Response object @router /get-stores [get]

func (*ApiController) GetString added in v1.833.89

func (c *ApiController) GetString(key string, def ...string) string

GetString is Input().Get with a fallback, for the reads that have a sensible default rather than an error.

func (*ApiController) GetSystemInfo

func (c *ApiController) GetSystemInfo()

GetSystemInfo @Title GetSystemInfo @Tag System API @Description get system info like CPU and memory usage @Success 200 {object} util.SystemInfo The Response object @router /get-system-info [get]

func (*ApiController) GetTask

func (c *ApiController) GetTask()

GetTask @Title GetTask @Tag Task API @Description get task @Param id query string true "The id (owner/name) of task" @Success 200 {object} object.Task The Response object @router /get-task [get]

func (*ApiController) GetTasks

func (c *ApiController) GetTasks()

GetTasks @Title GetTasks @Tag Task API @Description get tasks @Param owner query string true "The owner of task" @Success 200 {array} object.Task The Response object @router /get-tasks [get]

func (*ApiController) GetTemplate

func (c *ApiController) GetTemplate()

GetTemplate @Title GetTemplate @Tag Template API @Description get template @Param id query string true "The id of template" @Success 200 {object} object.Template The Response object @router /get-template [get]

func (*ApiController) GetTemplates

func (c *ApiController) GetTemplates()

GetTemplates @Title GetTemplates @Tag Template API @Description get templates @Param owner query string true "The owner of templates" @Success 200 {array} object.Template The Response object @router /get-templates [get]

func (*ApiController) GetTrafficGlobe added in v1.817.0

func (c *ApiController) GetTrafficGlobe()

GetTrafficGlobe returns the PUBLIC live request-geo aggregate for the world.hanzo.ai "Hanzo mode" globe: WHERE requests to api.hanzo.ai are coming from, as country/region points with per-service-class counts, plus headline throughput rates.

It is AUTH-exempt and BALANCE-exempt exactly like /v1/ai/router/stats?scope=platform:

  • auth: the controller name "traffic/globe" is neither a get-/update- CRUD name nor a super-admin/present-credential endpoint, so the authz filter passes it through, and this handler requires no principal.
  • balance: isBalanceExempt("/v1/ai/traffic/...") returns true.

It exposes ONLY aggregates — counts, rates, and country/region centroids — and NEVER any IP, per-request row, org, or user dimension (see object/traffic.go). Marketing telemetry; nothing sensitive.

@Title GetTrafficGlobe @Tag Traffic API @Description public live request-geo aggregate (country/region points + throughput totals); aggregates only, no IPs, no auth @Param window query int false "window size in minutes (default 60, capped at 1440)" @Success 200 {object} object.TrafficGlobe The Response object @router /traffic/globe [get]

func (*ApiController) GetTrainingContribution added in v1.811.0

func (c *ApiController) GetTrainingContribution()

GetTrainingContribution returns the caller's OWN org training-contribution opt-in (org > unset). Self-scoped via GetOrg — a customer reads only their OWN org's setting. Uses RequirePrincipal (session cookie OR verified Bearer JWT), NOT the session-only RequireAdmin, so this consent read serves BOTH the console (cookie) and the token-bearing account surfaces (Hanzo World carries an IAM Bearer, not the console cookie) with the SAME resolved identity. Unset reads as false — the privacy-safe default OFF.

@Title GetTrainingContribution @Tag Router API @Description get the caller's org training-data contribution opt-in @Success 200 {object} controllers.trainingContributionBody The Response object @router /get-training-contribution [get]

func (*ApiController) GetUsages

func (c *ApiController) GetUsages()

GetUsages @Title GetUsages @Tag Usage API @Description get usages @Param days query string true "days count" @Success 200 {array} object.Usage The Response object @router /get-usages [get]

func (*ApiController) GetUserTableInfos

func (c *ApiController) GetUserTableInfos()

GetUserTableInfos @Title GetUserTableInfos @Tag Usage API @Description get userTableInfos @Success 200 {array} object.Usage The Response object @router /get-usages [get]

func (*ApiController) GetUsers

func (c *ApiController) GetUsers()

GetUsers @Title GetUsers @Tag Usage API @Description get users @Success 200 {array} string The Response object @router /get-users [get]

func (*ApiController) GetVector

func (c *ApiController) GetVector()

func (*ApiController) GetVectors

func (c *ApiController) GetVectors()

GetVectors @Title GetVectors @Tag Vector API @Description get vectors @Success 200 {array} object.Vector The Response object @router /get-vectors [get]

func (*ApiController) GetVersionInfo

func (c *ApiController) GetVersionInfo()

GetVersionInfo @Title GetVersionInfo @Tag System API @Description get version info like IAM release version and commit ID @Success 200 {object} util.VersionInfo The Response object @router /get-version-info [get]

func (*ApiController) GetVideo

func (c *ApiController) GetVideo()

GetVideo @Title GetVideo @Tag Video API @Description get video @Param id query string true "The id of video" @Success 200 {object} object.Video The Response object @router /get-video [get]

func (*ApiController) GetVideos

func (c *ApiController) GetVideos()

GetVideos @Title GetVideos @Tag Video API @Description get videos @Param owner query string true "The owner of videos" @Success 200 {array} object.Video The Response object @router /get-videos [get]

func (*ApiController) GetVmDashboardUrl

func (c *ApiController) GetVmDashboardUrl()

GetVmDashboardUrl returns the URL of the Hanzo VM control plane dashboard.

@Title GetVmDashboardUrl @Tag VM API @Description get VM dashboard URL @Success 200 {object} Response The Response object @router /get-vm-dashboard-url [get]

func (*ApiController) GetWorkflow

func (c *ApiController) GetWorkflow()

GetWorkflow @Title GetWorkflow @Tag Workflow API @Description get workflow @Param id query string true "The id (owner/name) of workflow" @Success 200 {object} object.Workflow The Response object @router /get-workflow [get]

func (*ApiController) GetWorkflows

func (c *ApiController) GetWorkflows()

GetWorkflows @Title GetWorkflows @Tag Workflow API @Description get workflows @Param owner query string true "The owner of workflow" @Success 200 {array} object.Workflow The Response object @router /get-workflows [get]

func (*ApiController) Health

func (c *ApiController) Health()

Health @Title Health @Tag System API @Description check if the system is live @Success 200 {object} controllers.Response The Response object @router /health [get]

func (*ApiController) ImagesGenerations added in v1.790.1

func (c *ApiController) ImagesGenerations()

ImagesGenerations implements POST /v1/images/generations (OpenAI-compatible).

Body: {"model": "...", "prompt": "...", "n"?: int, "size"?: "1024x1024",

"response_format"?: "url"|"b64_json"}

It authenticates the caller, resolves the model to its upstream provider via the shared routing table (zen3-image* → do-ai fal diffusion), reserves the per-image budget, generates the image(s) through the do-ai async image client, records usage for billing, and returns the OpenAI images response. @Title ImagesGenerations @Tag OpenAI Compatible API @Description OpenAI compatible image generations API. @router /images/generations [post]

func (*ApiController) IndexDocs

func (c *ApiController) IndexDocs()

IndexDocs @Title IndexDocs @Tag Search Docs API @Description index documentation into Meilisearch and Qdrant @Param body body object.DocIndexRequest true "Index request" @Success 200 {object} controllers.Response The Response object @router /index [post]

func (*ApiController) IngestDocs added in v1.786.0

func (c *ApiController) IngestDocs()

IngestDocs @Title IngestDocs @Tag Docs Ingest API @Description Unified RAG ingest: parse + chunk + embed documents and pipe them

to BOTH Hanzo Vector (semantic) AND Hanzo Search (keyword) under the tenant
index {owner}-{store}-docs — the same index /v1/chat retrieval reads. The
source is pluggable: "upload" (inline files/documents), "github" (index a
repo), "crawl" (web), or "s3" (the store's object-storage space). The owner
is bound to the authenticated principal; the client-supplied owner is never
trusted.

@Param body body object.IngestRequest true "Ingest request" @Success 200 {object} object.IngestStats "Ingest statistics" @router /docs/ingest [post]

func (*ApiController) Input added in v1.833.89

func (c *ApiController) Input() url.Values

Input is every value the request carries by name, query and form merged, with the form winning — the same order net/http's ParseForm produces. Handlers read an identifier as Input().Get("id") whether it arrived as ?id=, as a form field, or as a route parameter the router bound.

func (*ApiController) IsAdmin

func (c *ApiController) IsAdmin() bool

func (*ApiController) IsCurrentUser

func (c *ApiController) IsCurrentUser(usernameInput string) bool

IsCurrentUser reports whether this request may act as usernameInput, and refuses the request when it may not.

It answers for NAMES, on both sides, and only for names. Empty used to pass: an unauthenticated request has no session username, so the comparison below read "" != "" and every anonymous caller was the current user of the empty user. The chat plane then wrote that onto a row whose answer bills `admin/` — the admin org's own pool wallet. A usernameInput carrying "/" is not a user either but a whole billing subject, and the admin branch below would wave it through.

func (*ApiController) IsPreviewMode

func (c *ApiController) IsPreviewMode() bool

func (*ApiController) IsSessionDuplicated

func (c *ApiController) IsSessionDuplicated()

IsSessionDuplicated @Title IsSessionDuplicated @Tag Session API @Description Check if there are other different sessions for one user in one application. @Param id query string true "The id(organization/application/user) of session" @Param sessionId query string true "sessionId to be checked" @Success 200 {array} string The Response object @router /is-session-duplicated [get]

func (*ApiController) ListFinetuneJobs added in v1.806.13

func (c *ApiController) ListFinetuneJobs()

ListFinetuneJobs returns the org's jobs, refreshing live status for active ones.

func (*ApiController) ListModels

func (c *ApiController) ListModels()

ListModels returns the list of available models from the routing table.

PUBLIC BY DESIGN, AND IT DOES NOT AUTHENTICATE — that is the whole contract, so it is stated here rather than left to be inferred. The catalogue is the same for everyone (listAvailableModels takes no principal), docs.hanzo.ai fetches it from the browser, and every policy layer around it says so: the authz filter lists "models" as public, filter_balance does not gate it, the rate limiter excludes it, and cloud's spend.Reachable carries /v1/models/ as "the model catalog the shell reads for discovery".

SO THE Authorization HEADER IS NOT AN ADMISSION CHECK HERE. It is read for ONE thing — annotating gated SKUs with the caller's own access standing — and annotation degrades to nothing when there is no verified principal.

A credential that is presented is verified, never merely shape-checked: a caller using /v1/models to ask "is my key working?" gets an honest answer, because a key that does not verify annotates nothing rather than reading as accepted.

@Title ListModels @Tag OpenAI Compatible API @Description Returns a list of all available models. Public — no authentication. @Success 200 {object} object @router /models [get]

func (*ApiController) MemoryDelete added in v1.785.11

func (c *ApiController) MemoryDelete()

MemoryDelete @Title MemoryDelete @Tag Memory API @Description delete one of the authenticated user's memories @Param body body controllers.memoryRequest true "id/name to delete" @Success 200 {object} controllers.Response The Response object @router /memory/delete [post]

func (*ApiController) MemoryFacts added in v1.785.11

func (c *ApiController) MemoryFacts()

MemoryFacts @Title MemoryFacts @Tag Memory API @Description list the authenticated user's stored facts @Param limit query string false "max results" @Success 200 {array} object.Memory The Response object @router /memory/facts [get]

func (*ApiController) MemoryList added in v1.785.11

func (c *ApiController) MemoryList()

MemoryList @Title MemoryList @Tag Memory API @Description list the authenticated user's memories, newest first @Param kind query string false "filter by kind" @Param limit query string false "max results" @Success 200 {array} object.Memory The Response object @router /memory/list [get]

func (*ApiController) MemoryRecall added in v1.785.11

func (c *ApiController) MemoryRecall()

MemoryRecall @Title MemoryRecall @Tag Memory API @Description recall recent/relevant memories for context injection; with q it @Description ranks semantically, without q it returns the most recent @Param q query string false "optional relevance query" @Param kind query string false "filter by kind" @Param limit query string false "max results" @Success 200 {array} object.Memory The Response object @router /memory/recall [get]

func (*ApiController) MemoryRemember added in v1.785.11

func (c *ApiController) MemoryRemember()

MemoryRemember @Title MemoryRemember @Tag Memory API @Description store a memory for the authenticated user @Param body body controllers.memoryRequest true "content, kind, metadata" @Success 200 {object} object.Memory The Response object @router /memory/remember [post]

func (*ApiController) MemorySearch added in v1.785.11

func (c *ApiController) MemorySearch()

MemorySearch @Title MemorySearch @Tag Memory API @Description search the authenticated user's memories (semantic, text fallback) @Param q query string true "search query" @Param kind query string false "filter by kind" @Param limit query string false "max results" @Success 200 {array} object.Memory The Response object @router /memory/search [get]

func (*ApiController) MemoryUpdate added in v1.785.11

func (c *ApiController) MemoryUpdate()

MemoryUpdate @Title MemoryUpdate @Tag Memory API @Description update one of the authenticated user's memories @Param body body controllers.memoryRequest true "id/name + fields to change" @Success 200 {object} controllers.Response The Response object @router /memory/update [post]

func (*ApiController) PageAsked added in v1.833.89

func (c *ApiController) PageAsked() int

PageAsked is the page the caller asked for, from the "p" query parameter. Zero when absent or unreadable, which the paginator clamps to the first page.

func (*ApiController) PostBackfillDOUsage added in v1.813.0

func (c *ApiController) PostBackfillDOUsage()

PostBackfillDOUsage @Title PostBackfillDOUsage @Tag Usage API @Description Super-admin: backfill the hanzo.cloud_usage ledger from DigitalOcean's billing API for (day) windows our native metering missed — GAPS ONLY (never double-counts a natively-metered day), PROVENANCE-tagged (source="do-backfill"), and IDEMPOTENT (re-running is a no-op). DRY-RUN by default: returns the rows/days/ totals it WOULD write and persists nothing unless dryRun=false is passed explicitly. @Param from query string false "window start (RFC3339, YYYY-MM-DD, or unix seconds; default 365d ago)" @Param to query string false "window end (RFC3339, YYYY-MM-DD, or unix seconds; default now)" @Param dryRun query string false "false to persist; anything else (default) plans only" @Param force query string false "true to import even days native metering already covers" @Success 200 {object} controllers.DOBackfillPlan The Response object @router /admin/usage/backfill-do [post]

func (*ApiController) QueryRecord

func (c *ApiController) QueryRecord()

QueryRecord @Title QueryRecord @Tag Record API @Description query record @Param id query string true "The id ( owner/name ) of the record" @Success 200 {object} object.Record The Response object @router /query-record [get]

func (*ApiController) QueryRecordSecond

func (c *ApiController) QueryRecordSecond()

QueryRecordSecond @Title QueryRecordSecond @Tag Record API @Description query record @Param id query string true "The id ( owner/name ) of the record" @Success 200 {object} object.Record The Response object @router /query-record-second [get]

func (*ApiController) RagContext added in v1.790.2

func (c *ApiController) RagContext()

RagContext @Title RagContext @Tag RAG API @Description Return every stored chunk of one file_id (full document context).

Consolidates the retired chat-rag-api GET /documents/{id}/context.

@Param file_id query string true "The file_id" @Param store query string false "Store slug (default rag-files)" @Success 200 {array} object.DocSearchResult "All chunks of the file" @router /rag/context [get]

func (*ApiController) RagDelete added in v1.790.2

func (c *ApiController) RagDelete()

RagDelete @Title RagDelete @Tag RAG API @Description Delete all chunks of one or more uploaded files (by file_id) from

the owner's Search+Vector index. Consolidates the retired chat-rag-api
DELETE /documents.

@Param body body controllers.ragDeleteBody true "Delete request" @Success 200 {object} controllers.Response The Response object @router /rag/delete [post]

func (*ApiController) RagEmbed added in v1.790.2

func (c *ApiController) RagEmbed()

RagEmbed @Title RagEmbed @Tag RAG API @Description Parse, chunk, and embed one uploaded file under its file_id into

the unified Search+Vector index, scoped to the authenticated owner. Provide
inline `content` or a `url` to fetch+parse (PDF/CSV/XLSX/PPTX/…). Re-embedding
the same file_id replaces its chunks. Consolidates the retired chat-rag-api
POST /embed and /local/embed.

@Param body body object.RagEmbedRequest true "Embed request" @Success 200 {object} object.RagEmbedResult "Embed result" @router /rag/embed [post]

func (*ApiController) RagQuery added in v1.790.2

func (c *ApiController) RagQuery()

RagQuery @Title RagQuery @Tag RAG API @Description Retrieve the top-K chunks relevant to a query, scoped to a single

uploaded file (`file_id`). Hybrid keyword+vector retrieval over the same
index. Consolidates the retired chat-rag-api POST /query.

@Param body body object.RagQueryRequest true "Query request" @Success 200 {array} object.DocSearchResult "Matching chunks" @router /rag/query [post]

func (*ApiController) RagQueryMultiple added in v1.790.2

func (c *ApiController) RagQueryMultiple()

RagQueryMultiple @Title RagQueryMultiple @Tag RAG API @Description Retrieve the top-K chunks relevant to a query, scoped to a SET of

uploaded files (`file_ids`). Consolidates the retired chat-rag-api POST
/query_multiple. Shares one retrieval path with /rag/query.

@Param body body object.RagQueryRequest true "Query request" @Success 200 {array} object.DocSearchResult "Matching chunks" @router /rag/query-multiple [post]

func (*ApiController) RefreshFileVectors

func (c *ApiController) RefreshFileVectors()

RefreshFileVectors @Title RefreshFileVectors @Tag File API @Description refresh file vectors @Param body body object.File true "The details of the file object" @Success 200 {object} controllers.Response The Response object @router /refresh-file-vectors [post]

func (*ApiController) RefreshMcpTools

func (c *ApiController) RefreshMcpTools()

RefreshMcpTools @Title RefreshMcpTools @Tag Provider API @Description refresh Mcp tools @Param body body object.Provider true "The details of the provider" @Success 200 {object} controllers.Response The Response object @router /refresh-mcp-tools [post]

func (*ApiController) RefreshModelPricing added in v1.801.0

func (c *ApiController) RefreshModelPricing()

RefreshModelPricing forces a live pricing refresh from the configured pricing service, so the catalogue's rates match the source without waiting for the cycle. @Title RefreshModelPricing @Tag Admin @Description Force a live pricing refresh from the configured pricing service. @Success 200 {object} controllers.Response @router /admin/refresh-model-pricing [post]

func (*ApiController) RefreshStoreVectors

func (c *ApiController) RefreshStoreVectors()

RefreshStoreVectors @Title RefreshStoreVectors @Tag Store API @Description refresh store vectors @Param body body object.Store true "The details of the store" @Success 200 {object} controllers.Response The Response object @router /refresh-store-vectors [post]

func (*ApiController) ReloadModelConfig

func (c *ApiController) ReloadModelConfig()

ReloadModelConfig reloads the model configuration from YAML and refreshes live pricing, so a catalogue change takes effect without a restart. @Title ReloadModelConfig @Tag Admin @Description Reload model configuration from YAML and refresh live pricing. @Success 200 {object} controllers.Response @router /admin/reload-model-config [post]

func (*ApiController) RequestModelAccess added in v1.809.2

func (c *ApiController) RequestModelAccess()

RequestModelAccess records the caller's waitlist request for a gated model and answers their new standing. Authed, idempotent, and self-scoped: the row is keyed to the caller's own org and identity, never to a body-supplied owner.

func (*ApiController) RequireAdmin

func (c *ApiController) RequireAdmin() bool

func (*ApiController) RequirePrincipal added in v1.807.1

func (c *ApiController) RequirePrincipal() (*iam.User, bool)

RequirePrincipal resolves the request principal from EITHER the browser session cookie OR a verified Bearer JWT (c.principalUser), returning a real 401 when neither is present. It is the Bearer-aware sibling of RequireSignedInUser: an endpoint that must serve BOTH the console (session cookie) and the token-bearing surfaces (app / chat / billing, which carry an IAM Bearer, not the console cookie) with the SAME resolved identity uses this. The Bearer branch is signature- AND issuer/audience-validated via object.ParseAndValidateJWT (never raw iam.ParseJwtToken), so a forged token cannot pose as anyone.

The returned user is the SOLE authority for any downstream org/role scope decision — the caller MUST derive scope from THIS user (its Owner, its role via util.IsSuperAdmin), NEVER from a request header or query param. That is what keeps a Bearer-reachable, org-scoped read tenant-safe.

func (*ApiController) RequireSessionOwner

func (c *ApiController) RequireSessionOwner() (string, bool)

RequireSessionOwner ensures the caller is authenticated and returns their org owner. IAM headers are trusted when injected by the gateway, but session auth is primary here.

func (*ApiController) RequireSignedIn

func (c *ApiController) RequireSignedIn() (string, bool)

func (*ApiController) RequireSignedInUser

func (c *ApiController) RequireSignedInUser() (*iam.User, bool)

func (*ApiController) RequireSuperAdmin added in v1.804.0

func (c *ApiController) RequireSuperAdmin() bool

RequireSuperAdmin is the controller-level self-guard for platform-sensitive endpoints (provider-admin, upstream-key/topology config). It mirrors the authz filter's superAdminEndpoints gate EXACTLY — same principal (session or VERIFIED Bearer JWT via c.principalUser) and same policy (util.IsSuperAdmin) — so it is belt-AND-suspenders: even if the filter is ever bypassed (e.g. a path-normalization disagreement), the controller still refuses. Fail-closed: no principal → 401, authenticated non-super-admin → 403. Unlike RequireAdmin it is NOT relaxed by preview mode and checks GLOBAL (platform) admin, not org admin — these routes govern the primary provider that backs the whole model catalog.

func (*ApiController) Rerank added in v1.785.10

func (c *ApiController) Rerank()

Rerank implements POST /v1/rerank (Cohere/Jina-compatible).

Body: {"model": "...", "query": "...", "documents": ["...", ...]|[{"text":"..."}],

"top_n"?: int, "return_documents"?: bool}

Response: {"object":"list","model":...,"results":[{"index","relevance_score","document"?}],"usage":{...}}

Backend selection is provider-driven (one endpoint, one contract):

  • If the model routes to a native rerank provider (Jina/Cohere/Voyage) the request is proxied to that provider's /rerank endpoint.
  • Otherwise scores are computed as a real bi-encoder ranking: embed the query and documents through the resolved embedding model and rank by cosine similarity. No rerank-specific key required.

func (*ApiController) ResponseAudio

func (c *ApiController) ResponseAudio(audioData []byte, contentType string, filename string)

func (*ApiController) ResponseAuthError added in v1.785.10

func (c *ApiController) ResponseAuthError(err error)

ResponseAuthError renders an error from the auth / routing path with its carried HTTP status (401 / 402 / 400 / 500). It never emits 200, so an invalid key, an empty balance, or a bad model is unambiguous to OpenAI-compatible clients. This is the ONE renderer for that surface (chat, embeddings, rerank).

func (*ApiController) ResponseError

func (c *ApiController) ResponseError(error string, data ...any)

ResponseError writes the envelope with HTTP 200: the admin contract, where the envelope's own Status field carries the failure and the transport says nothing. The React admin reads that field, so this is the shape it expects.

func (*ApiController) ResponseErrorStream

func (c *ApiController) ResponseErrorStream(message *object.Message, errorText string)

ResponseErrorStream tells a client still holding the request's own connection.

func (*ApiController) ResponseErrorWithStatus added in v1.785.10

func (c *ApiController) ResponseErrorWithStatus(status int, error string, data ...any)

ResponseErrorWithStatus writes the envelope with an explicit HTTP status, which is what the OpenAI-compatible /v1 handlers need: a missing or invalid Bearer token is a 401 on the wire, not a 200 carrying a sad sentence.

The status is an ARGUMENT of the write, and has to be. This used to set it on the response and then call ResponseError to write the body — but a write takes the status too, so the second one silently replaced the first with 200 and every refusal in the service answered OK. A denial that arrives as a success is worse than an outage: the client reads 200 and believes it.

func (*ApiController) ResponseFailure added in v1.833.37

func (c *ApiController) ResponseFailure(err error)

ResponseFailure renders a typed failure with the status AND the machine name it carries. ResponseError writes neither: it answers 200 with a message, so a completion that no provider could serve reached clients as a success whose body had no choices in it.

func (*ApiController) ResponseForbidden added in v1.785.11

func (c *ApiController) ResponseForbidden(error string, data ...any)

ResponseForbidden renders an authorization denial (authenticated but not permitted) as a real HTTP 403 — never The router's default 200. Same body shape.

func (*ApiController) ResponseModelFailure added in v1.833.252

func (c *ApiController) ResponseModelFailure(err error)

ResponseModelFailure renders a model call that nothing answered, with the status a client should see for it (statusForModelError: an upstream 429 stays a 429, a vendor's 402 is our 503) and the machine name it carries.

func (*ApiController) ResponseOk

func (c *ApiController) ResponseOk(data ...any)

func (*ApiController) ResponseUnauthorized added in v1.785.11

func (c *ApiController) ResponseUnauthorized(error string, data ...any)

ResponseUnauthorized renders an authentication denial (no/invalid session or credential) as a real HTTP 401 — never The router's default 200. Same body shape.

func (*ApiController) Responses added in v1.806.15

func (c *ApiController) Responses()

Responses implements POST /v1/responses. The converted request is completed by the chat path, which is handed a sink saying where the answer goes: a stream is translated as it is produced, a whole body is translated entire.

func (*ApiController) RetrieveThreeD added in v1.833.218

func (c *ApiController) RetrieveThreeD()

RetrieveThreeD implements GET /v1/3d/:id (Retrieve 3D status).

func (*ApiController) RetrieveVideo added in v1.800.0

func (c *ApiController) RetrieveVideo()

RetrieveVideo implements GET /v1/videos/{id} — poll a job's status.

It authenticates the caller, verifies they OWN the job (the caller's billing subject must equal the job's), performs ONE upstream status poll, and — the first time the job is observed completed — settles the reservation with the actual cost and records the billable usage event (exactly once). Returns the OpenAI-shaped video object.

@Title RetrieveVideo @Tag OpenAI Compatible API @Description Retrieve the status of an async video generation job. @router /videos/:id [get]

func (*ApiController) RouteAuto added in v1.833.237

func (c *ApiController) RouteAuto()

RouteAuto resolves a completion that names `auto` or `zen-router` to the SKU that will serve it, and rewrites the request to name that SKU. It runs ahead of the balance gate, so the gate, the plan limits and the handler all price, admit and serve the model that answers; the virtual id is never priced. The handler keeps the request id and task decided here (see chatCompletions).

Resolution calls the router engine with the caller's prompt and records a RoutingEvent, so it runs only for a caller that authenticates. A request it cannot resolve (no credential, routing off for the org, no servable model, an unreadable body) runs as sent. A /v1/responses body is read in its own dialect and rewritten in it. The body is read decoded, and a rewritten body is sent on plain.

func (*ApiController) RouterCatalogApply added in v1.833.274

func (c *ApiController) RouterCatalogApply()

RouterCatalogApply applies an edited catalog to one family, made from its newest version, and records the new version. SuperAdmin only.

func (*ApiController) RouterCatalogPropose added in v1.833.274

func (c *ApiController) RouterCatalogPropose()

RouterCatalogPropose answers the diff an edited catalog would apply to a family, and the version it would be made from. Nothing is applied. SuperAdmin only.

func (*ApiController) RouterCatalogRead added in v1.833.274

func (c *ApiController) RouterCatalogRead()

RouterCatalogRead lists the Zen and Enso routing catalogs: what each serves, its accounts and model health, and its version history. SuperAdmin only.

func (*ApiController) RouterCatalogRollback added in v1.833.274

func (c *ApiController) RouterCatalogRollback()

RouterCatalogRollback applies an earlier version of a family's catalog again, as a new version. SuperAdmin only.

func (*ApiController) RouterCatalogTest added in v1.833.274

func (c *ApiController) RouterCatalogTest()

RouterCatalogTest sends one short turn to a SKU through its family and answers which upstream wrote it and how long it took. SuperAdmin only.

func (*ApiController) RouterConfigBridge added in v1.829.6

func (c *ApiController) RouterConfigBridge()

RouterConfigBridge is the HTTP transport binding for the RESTful router-config nouns (/v1/ai/router/{policy,defaults,ledger,rewards,artifact-meta} and /v1/ai/org/settings[/list]). It dispatches IN-PROCESS through dispatchGateway — the SAME canonical ZAP gateway registry (zap_registry.go) that the MsgType 200 handler serves over the gateway transport. The native ZAP handler is the ONE and ONLY implementation of these routes; this is purely the api.hanzo.ai HTTP binding, so there is NO controller twin to drift from and the split-brain the router refactor removed stays removed.

Why a bridge and not a twin controller method: one handler serves both transports, so the HTTP route and the ZAP message read and write router settings through the same code and cannot come to disagree about them. Routing these nouns through the ZAP handler over one adapter keeps a single source of truth.

Identity is the request's own Bearer credential (Authorization header), which the native handlers resolve exactly as the gateway does — every caller (console, chat, app) already sends it. The dispatched handler returns a ZAP message whose status is field 0 and body is field 4 (BuildCloudResponse / BuildGatewayResponse layout); both are relayed verbatim. The route is mapped "*" (any verb) because the native handler is method-aware: /v1/ai/router/policy splits GET (read) vs PUT (write), /v1/ai/org/settings GET/PUT/DELETE, and returns 405 for a verb it does not own.

func (*ApiController) ScanAsset

func (c *ApiController) ScanAsset()

ScanAsset @Title ScanAsset @Tag Asset API @Description unified API for scanning assets (combines test-scan and start-scan functionality) @Param provider query string true "The provider ID (owner/name)" @Param scan query string false "The scan ID (owner/name) for saving results" @Param targetMode query string true "Target mode: 'Manual Input' or 'Asset'" @Param target query string false "Manual input target (IP address or network range)" @Param asset query string false "Asset ID (owner/name) for Asset mode" @Param command query string false "Scan command with optional %s placeholder for target" @Param saveToScan query string false "Whether to save results to scan object (true/false)" @Success 200 {object} controllers.Response The Response object @router /scan-asset [post]

func (*ApiController) ScanAssets

func (c *ApiController) ScanAssets()

ScanAssets @Title ScanAssets @Tag Asset API @Description scan assets from a cloud provider @Param owner query string true "The owner" @Param provider query string true "The provider name" @Success 200 {object} controllers.Response The Response object @router /scan-assets [post]

func (*ApiController) SearchDocs

func (c *ApiController) SearchDocs()

SearchDocs @Title SearchDocs @Tag Search Docs API @Description search documentation using hybrid fulltext + vector search @Param body body object.DocSearchRequest true "Search request" @Success 200 {array} object.DocSearchResult The search results (raw array, not wrapped) @router /search [post]

func (*ApiController) SearchDocsStats

func (c *ApiController) SearchDocsStats()

SearchDocsStats @Title SearchDocsStats @Tag Search Docs API @Description get search index statistics @Success 200 {object} object.DocStatsResponse The stats response @router /search/stats [get]

func (*ApiController) SearchHfDatasets added in v1.806.13

func (c *ApiController) SearchHfDatasets()

SearchHfDatasets proxies a HuggingFace dataset search (dataset picker).

func (*ApiController) SearchHfModels added in v1.806.13

func (c *ApiController) SearchHfModels()

SearchHfModels proxies a HuggingFace model search (base-model picker).

func (*ApiController) SendStreamWriter added in v1.833.229

func (c *ApiController) SendStreamWriter(fn func(*bufio.Writer)) error

SendStreamWriter is zip's, with this request's answer shape applied to every stream it writes.

The Responses bridge used to be installed by ONE path — the native text completion — while the family relay, the tool-call proxy and the vision proxy each opened their own stream and wrote upstream chat SSE straight to the client. So /v1/responses answered `chat.completion.chunk` for every model a family or a proxy serves, which is nearly all of them, and any request carrying tools: a Responses client (Hanzo Dev, the OpenAI SDK) saw no response.* event, dropped every chunk, and failed on "stream closed before response.completed".

Here the bridge wraps the writer each path is handed, so the translation is a property of the request rather than of which path happened to serve it. A path flushes its own buffered writer after each chunk; the bridge emits and flushes each Responses event as the chunk arrives, so the answer still streams.

func (*ApiController) SetPrimaryAdminProvider added in v1.790.5

func (c *ApiController) SetPrimaryAdminProvider()

SetPrimaryAdminProvider @Title SetPrimaryAdminProvider @Tag Provider Admin API @Description Make one admin-owned Model provider the primary (IsDefault=true)

and clear IsDefault on all other Model providers, so EXACTLY ONE primary
exists. Returns the full updated management list.

@Param body body controllers.setPrimaryRequest true "provider name" @Success 200 {array} controllers.adminProviderView The Response object @router /admin/providers/primary [post]

func (*ApiController) SetSessionClaims

func (c *ApiController) SetSessionClaims(claims *iam.Claims)

SetSessionClaims writes who the caller is for the rest of their visit, as the cookie that carries their token. A nil claim ends the visit.

It takes claims rather than a token because the callers hold claims; the token they were parsed from rides along on AccessToken, and that is what the browser gets back.

func (*ApiController) SetSessionUser

func (c *ApiController) SetSessionUser(user *iam.User)

SetSessionUser refreshes the identity on the visit's own credential. A nil user ends it.

func (*ApiController) Signin

func (c *ApiController) Signin()

Signin @Title Signin @Tag Account API @Description sign in @Param code query string true "code of account" @Param state query string true "state of account" @Success 200 {object} iam.Claims The Response object @router /signin [post]

func (*ApiController) Signout

func (c *ApiController) Signout()

Signout @Title Signout @Tag Account API @Description sign out @Success 200 {object} controllers.Response The Response object @router /signout [post]

func (*ApiController) StartConnection

func (c *ApiController) StartConnection()

StartConnection @Title StartConnection @Tag Connection API @Description start connection @Param id query string true "The id of connection" @Success 200 {object} Response @router /start-connection [post]

func (*ApiController) StopConnection

func (c *ApiController) StopConnection()

StopConnection @Title StopConnection @Tag Connection API @Description stop connection @Param id query string true "The id of connection" @Success 200 {object} Response @router /stop-connection [post]

func (*ApiController) T

func (c *ApiController) T(error string) string

func (*ApiController) ThreeDContent added in v1.833.218

func (c *ApiController) ThreeDContent()

ThreeDContent implements GET /v1/3d/:id/content (Download 3D splat/glb content).

func (*ApiController) ThreeDGenerations added in v1.833.218

func (c *ApiController) ThreeDGenerations()

ThreeDGenerations implements POST /v1/3d/generations (Text/Image to 3D & Gaussian Splats).

@Title ThreeDGenerations @Tag 3D Generation API @Description Multi-modal 3D asset generation & Gaussian Splats @router /3d/generations [post]

func (*ApiController) ToggleAdminProvider added in v1.790.5

func (c *ApiController) ToggleAdminProvider()

ToggleAdminProvider @Title ToggleAdminProvider @Tag Provider Admin API @Description Enable/disable an admin-owned Model provider (sets State to

"Active"/"Disabled") via the SAME store the generic CRUD uses. Persists
across restarts (init.go never clobbers State on an existing record).
Returns the updated management view for that provider.

@Param body body controllers.toggleProviderRequest true "provider name + enabled flag" @Success 200 {object} controllers.adminProviderView The Response object @router /admin/providers/toggle [post]

func (*ApiController) TunnelMonitor

func (c *ApiController) TunnelMonitor()

func (*ApiController) UndeployApplication

func (c *ApiController) UndeployApplication()

UndeployApplication @Title UndeployApplication @Tag Application API @Description undeploy application synchronously @Param body body object.Application true "The details of the application" @Success 200 {object} controllers.Response The Response object @router /undeploy-application [post]

func (*ApiController) UpdateApplication

func (c *ApiController) UpdateApplication()

UpdateApplication @Title UpdateApplication @Tag Application API @Description update application @Param id query string true "The id (owner/name) of the application" @Param body body object.Application true "The details of the application" @Success 200 {object} controllers.Response The Response object @router /update-application [post]

func (*ApiController) UpdateArticle

func (c *ApiController) UpdateArticle()

UpdateArticle @Title UpdateArticle @Tag Article API @Description update article @Param id query string true "The id (owner/name) of the article" @Param body body object.Article true "The details of the article" @Success 200 {object} controllers.Response The Response object @router /update-article [post]

func (*ApiController) UpdateAsset

func (c *ApiController) UpdateAsset()

UpdateAsset @Title UpdateAsset @Tag Asset API @Description update asset @Param id query string true "The id ( owner/name ) of the asset" @Param body body object.Asset true "The details of the asset" @Success 200 {object} controllers.Response The Response object @router /update-asset [post]

func (*ApiController) UpdateChat

func (c *ApiController) UpdateChat()

UpdateChat @Title UpdateChat @Tag Chat API @Description update Chat @Param id query string true "The id (owner/name) of the chat" @Param body body object.Chat true "The details of the chat" @Success 200 {object} controllers.Response The Response object @router /update-chat [post]

func (*ApiController) UpdateConnection

func (c *ApiController) UpdateConnection()

UpdateConnection @Title UpdateConnection @Tag Connection API @Description update connection @Param id query string true "The id of connection" @Param body body object.Connection true "The connection object" @Success 200 {object} Response @router /update-connection [post]

func (*ApiController) UpdateFile

func (c *ApiController) UpdateFile()

UpdateFile @Title UpdateFile @Tag File API @Description update file object @Param id query string true "The id (owner/name) of the file object" @Param body body object.File true "The details of the file object" @Success 200 {object} controllers.Response The Response object @router /update-file [post]

func (*ApiController) UpdateForm

func (c *ApiController) UpdateForm()

UpdateForm @Title UpdateForm @Tag Form API @Description update form @Param id query string true "The id (owner/name) of the form" @Param body body object.Form true "The details of the form" @Success 200 {object} controllers.Response The Response object @router /update-form [post]

func (*ApiController) UpdateGraph

func (c *ApiController) UpdateGraph()

UpdateGraph @Title UpdateGraph @Tag Graph API @Description update Graph @Param id query string true "The id (owner/name) of the Graph" @Param body body object.Graph true "The details of the Graph" @Success 200 {object} controllers.Response The Response object @router /update-Graph [post]

func (*ApiController) UpdateMessage

func (c *ApiController) UpdateMessage()

UpdateMessage @Title UpdateMessage @Tag Message API @Description update message @Param id query string true "The id (owner/name) of the message" @Param body body object.Message true "The details of the message" @Success 200 {object} controllers.Response The Response object @router /update-message [post]

func (*ApiController) UpdateModelRoute

func (c *ApiController) UpdateModelRoute()

UpdateModelRoute @Title UpdateModelRoute @Tag ModelRoute API @Description update a model route @Param owner query string true "The owner (org)" @Param modelName query string true "The model name" @Param body body object.ModelRoute true "The details of the model route" @Success 200 {object} controllers.Response The Response object @router /update-model-route [post]

func (*ApiController) UpdateNode

func (c *ApiController) UpdateNode()

UpdateNode @Title UpdateNode @Tag Node API @Description update node @Param id query string true "The id ( owner/name ) of the node" @Param body body object.Node true "The details of the node" @Success 200 {object} controllers.Response The Response object @router /update-node [post]

func (*ApiController) UpdatePreferences added in v1.785.10

func (c *ApiController) UpdatePreferences()

UpdatePreferences persists user customizations (favorites, layout, etc.) onto the signed-in user's IAM account so they follow the user across every product and every device/login.

SELF-SCOPED BY DESIGN: the target user is taken from the session, never from the request body — a caller can only ever change their own preferences. The posted JSON object is SHALLOW-MERGED into the existing preferences by top-level key, so one product (or device) writing its keys never clobbers another's. Persisted column-scoped (`properties` only) so no other user field is touched. Returns the merged preferences object.

@Title UpdatePreferences @Tag Account API @Description persist the signed-in user's cross-product preferences @Success 200 {object} object the merged preferences @router /update-preferences [post]

func (*ApiController) UpdateProvider

func (c *ApiController) UpdateProvider()

UpdateProvider @Title UpdateProvider @Tag Provider API @Description update provider @Param id query string true "The id (owner/name) of the provider" @Param body body object.Provider true "The details of the provider" @Success 200 {object} controllers.Response The Response object @router /update-provider [post]

func (*ApiController) UpdateRecord

func (c *ApiController) UpdateRecord()

UpdateRecord @Title UpdateRecord @Tag Record API @Description update record @Param id query string true "The id ( owner/name ) of the record" @Param body body object.Record true "The details of the record" @Success 200 {object} controllers.Response The Response object @router /update-record [post]

func (*ApiController) UpdateScale

func (c *ApiController) UpdateScale()

UpdateScale @router /update-scale [post]

func (*ApiController) UpdateScan

func (c *ApiController) UpdateScan()

UpdateScan @Title UpdateScan @Tag Scan API @Description update scan @Param id query string true "The id ( owner/name ) of the scan" @Param body body object.Scan true "The details of the scan" @Success 200 {object} controllers.Response The Response object @router /update-scan [post]

func (*ApiController) UpdateSession

func (c *ApiController) UpdateSession()

UpdateSession @Title UpdateSession @Tag Session API @Description Update session for one user in one application. @Param id query string true "The id(organization/application/user) of session" @Success 200 {array} string The Response object @router /update-session [post]

func (*ApiController) UpdateStore

func (c *ApiController) UpdateStore()

UpdateStore @Title UpdateStore @Tag Store API @Description update store @Param id query string true "The id (owner/name) of the store" @Param body body object.Store true "The details of the store" @Success 200 {object} controllers.Response The Response object @router /update-store [post]

func (*ApiController) UpdateTask

func (c *ApiController) UpdateTask()

UpdateTask @Title UpdateTask @Tag Task API @Description update task @Param id query string true "The id (owner/name) of the task" @Param body body object.Task true "The details of the task" @Success 200 {object} controllers.Response The Response object @router /update-task [post]

func (*ApiController) UpdateTemplate

func (c *ApiController) UpdateTemplate()

UpdateTemplate @Title UpdateTemplate @Tag Template API @Description update template @Param id query string true "The id (owner/name) of the template" @Param body body object.Template true "The details of the template" @Success 200 {object} controllers.Response The Response object @router /update-template [post]

func (*ApiController) UpdateTrainingContribution added in v1.811.0

func (c *ApiController) UpdateTrainingContribution()

UpdateTrainingContribution upserts the caller's OWN org training-contribution opt-in. The owner is forced to GetOrg() (any owner in the body is ignored, and a spoofed X-Org-Id is ignored for a non-super-admin), and the other OrgSettings fields (AutoRouting / DefaultSessionRouting / RouterPrefer) are preserved — the opt-in is an orthogonal concern. Self-scoped via RequirePrincipal (session cookie OR verified Bearer JWT), so the account-settings consent toggle works identically from the console and from Hanzo World; the write only ever touches the principal's OWN org.

@Title UpdateTrainingContribution @Tag Router API @Description opt the caller's org in/out of contributing routing events to the shared retrain @Param body body controllers.trainingContributionBody true "the opt-in state" @Success 200 {object} controllers.trainingContributionBody The resolved state @router /update-training-contribution [post]

func (*ApiController) UpdateTreeFile

func (c *ApiController) UpdateTreeFile()

UpdateTreeFile @Title UpdateTreeFile @Tag Tree File API @Description update tree file @Param storeId query string true "The store id of the file" @Param key query string true "The key of the file" @Param body body object.TreeFile true "The details of the Tree File" @Success 200 {object} controllers.Response The Response object @router /update-tree-file [post]

func (*ApiController) UpdateVector

func (c *ApiController) UpdateVector()

UpdateVector @Title UpdateVector @Tag Vector API @Description update vector @Param id query string true "The id (owner/name) of the vector" @Param body body object.Vector true "The details of the vector" @Success 200 {object} controllers.Response The Response object @router /update-vector [post]

func (*ApiController) UpdateVideo

func (c *ApiController) UpdateVideo()

UpdateVideo @Title UpdateVideo @Tag Video API @Description update video @Param id query string true "The id (owner/name) of the video" @Param body body object.Video true "The details of the video" @Success 200 {object} controllers.Response The Response object @router /update-video [post]

func (*ApiController) UpdateWorkflow

func (c *ApiController) UpdateWorkflow()

UpdateWorkflow @Title UpdateWorkflow @Tag Workflow API @Description update workflow @Param id query string true "The id (owner/name) of the workflow" @Param body body object.Workflow true "The details of the workflow" @Success 200 {object} controllers.Response The Response object @router /update-workflow [post]

func (*ApiController) UploadFile

func (c *ApiController) UploadFile()

UploadFile @Title UploadFile @Tag File API @Description upload file to IAM storage @Param file formData string true "The base64 encoded file data" @Param type formData string true "The file type/extension" @Param name formData string true "The file name" @Success 200 {object} controllers.Response The Response object @router /upload-file [post]

func (*ApiController) UploadTaskDocument

func (c *ApiController) UploadTaskDocument()

UploadTaskDocument @Title UploadTaskDocument @Tag Task API @Description upload document for a task and parse its text @Param id query string true "The id (owner/name) of the task" @Param file formData string true "The base64 encoded file data" @Param type formData string true "The file type/extension" @Param name formData string true "The file name" @Success 200 {object} controllers.Response The Response object @router /upload-task-document [post]

func (*ApiController) UploadVideo

func (c *ApiController) UploadVideo()

UploadVideo @Title UploadVideo @Tag Video API @Description upload video @Param file formData file true "The video file to upload" @Success 200 {object} string "The fileId of the uploaded video" @router /upload-video [post]

func (*ApiController) VideoContent added in v1.800.0

func (c *ApiController) VideoContent()

VideoContent implements GET /v1/videos/{id}/content — download the finished MP4.

It authenticates + ownership-checks the caller, then proxies the upstream /content endpoint (bounded by the download concurrency ceiling) and streams the raw video bytes back inline. A successful download also bills the job once (for the client that downloads without first polling to completion) — idempotent with the poll path via job.markCompleted.

@Title VideoContent @Tag OpenAI Compatible API @Description Download the finished MP4 of a completed video generation job. @router /videos/:id/content [get]

func (*ApiController) VideosGenerations added in v1.790.4

func (c *ApiController) VideosGenerations()

VideosGenerations implements POST /v1/videos/generations — the ASYNC create.

Body: {"model": "...", "prompt": "...", "size"?: "1280x720", "seconds"?: int}

It authenticates the caller, resolves the model to its upstream provider via the shared routing table (zen3-video* / wan2-2-t2v-a14b → the spark-video backend), reserves the per-video budget (the balance gate), creates ONE upstream job, registers it in the in-pod store, and returns the OpenAI-shaped video object with status "queued" IMMEDIATELY. The client then polls GET /v1/videos/{id} and downloads GET /v1/videos/{id}/content. Nothing is billed here — the debit lands on completion.

@Title VideosGenerations @Tag OpenAI Compatible API @Description OpenAI Sora-style async text-to-video: create a generation job. @router /videos/generations [post]

type BrandIAM added in v1.795.0

type BrandIAM struct {
	// Brand is the canonical brand key (hanzo|lux|zoo|pars).
	Brand string
	// Endpoint is the IAM OIDC base the code exchange + userinfo target. In
	// cluster the exchange rides the internal IAM service (IAM_URL); the public
	// issuer host is the value tokens carry (Issuer).
	Endpoint string
	// Issuer is the JWT `iss` a brand's tokens carry (e.g. https://lux.id).
	Issuer string
	// ClientID is the brand's OAuth client_id / IAM application name AND the `aud`
	// its tokens carry (client_id == app == aud, HIP-0111).
	ClientID string
	// ClientSecret is the brand's confidential-client secret (from env/KMS). Empty
	// for a brand whose secret is not provisioned -- the exchange then fails closed
	// with a clear error, never a fabricated token.
	ClientSecret string
	// Org is the brand's IAM organization slug (the tenant owner).
	Org string
}

BrandIAM is a brand's resolved IAM identity for the OAuth code exchange and token validation. ClientID doubles as the OAuth `aud`/client_id; Issuer is the canonical OIDC `iss` a brand's tokens carry.

type CacheTTLs

type CacheTTLs struct {
	PricingTTL string `yaml:"pricing_ttl"`
}

CacheTTLs defines TTL durations for cached data.

type CacheWrites added in v1.833.266

type CacheWrites struct {
	Minutes int `json:"ephemeral_5m_input_tokens"`
	Hour    int `json:"ephemeral_1h_input_tokens"`
}

CacheWrites is cache_creation: the cache writes kept five minutes and one hour.

type CarrierWriter

type CarrierWriter struct {
	// contains filtered or unexported fields
}

func (*CarrierWriter) Flush

func (w *CarrierWriter) Flush()

func (*CarrierWriter) MessageString

func (w *CarrierWriter) MessageString() string

func (*CarrierWriter) Write

func (w *CarrierWriter) Write(p []byte) (n int, err error)

type Cleaner

type Cleaner struct {
	// contains filtered or unexported fields
}

func NewCleaner

func NewCleaner(bufferSize int) *Cleaner

func (*Cleaner) AddData

func (c *Cleaner) AddData(data string)

func (*Cleaner) CleanString

func (c *Cleaner) CleanString(data string) string

func (*Cleaner) GetCleanedData

func (c *Cleaner) GetCleanedData() string

type DOBackfillOptions added in v1.813.0

type DOBackfillOptions struct {
	From   time.Time // window start (inclusive day)
	To     time.Time // window end (inclusive day)
	DryRun bool      // when true, plan only — write nothing (the default)
	Force  bool      // when true, import even days native metering already covers
}

DOBackfillOptions is the resolved, already-authorized backfill request.

type DOBackfillPlan added in v1.813.0

type DOBackfillPlan struct {
	DryRun                   bool            `json:"dryRun"`
	Force                    bool            `json:"force"`
	Provider                 string          `json:"provider"`
	Source                   string          `json:"source"`
	From                     string          `json:"from"` // RFC3339 (UTC)
	To                       string          `json:"to"`   // RFC3339 (UTC)
	Rows                     []DOBackfillRow `json:"rows"`
	Days                     int             `json:"days"`
	Models                   int             `json:"models"`
	TotalCents               int64           `json:"totalCents"`
	Written                  int             `json:"written"`
	SkippedNativelyCovered   int             `json:"skippedNativelyCovered"`
	SkippedAlreadyBackfilled int             `json:"skippedAlreadyBackfilled"`
	InvoicesScanned          int             `json:"invoicesScanned"`
	InvoiceFetchErrors       int             `json:"invoiceFetchErrors"`
	Note                     string          `json:"note"`
}

DOBackfillPlan is the importer's full answer: what it would write / wrote, plus the honest accounting of everything it skipped and why. Returned by both the dry-run and the write path so the console shows an identical shape either way.

func RunDOBackfill added in v1.813.0

func RunDOBackfill(ctx context.Context, opts DOBackfillOptions) (DOBackfillPlan, error)

RunDOBackfill is the orchestration: fetch DO spend, read the ledger's native + already-backfilled coverage, plan the gap-fill (pure), and — only when dryRun is false — persist. It is a thin seam over the pure/testable pieces; the DO fetch and the planning are exercised directly by the tests, this glue is not.

type DOBackfillRow added in v1.813.0

type DOBackfillRow struct {
	Day       string `json:"day"` // YYYY-MM-DD (UTC)
	Model     string `json:"model"`
	Provider  string `json:"provider"`
	CostCents int64  `json:"costCents"`
	Source    string `json:"source"`
	ID        string `json:"id"` // deterministic — re-deriving it for the same (day,model) is stable
}

DOBackfillRow is one (day, model) row the importer would write (dry-run) or wrote.

type FallbackDef

type FallbackDef struct {
	Provider string `yaml:"provider"`
	Upstream string `yaml:"upstream"`
	// ContextWindow is the window THIS provider serves the model at. The same
	// model is served at different sizes by different providers — DO serves
	// glm-5.2 at 262144 while the model itself is a 1M-context model — so the
	// window belongs to the (provider, upstream) pair, not to the model. A
	// fallback that reaches a bigger window declares it here; 0 inherits the
	// primary route's window.
	ContextWindow int `yaml:"context_window,omitempty"`
}

FallbackDef describes an alternate provider+upstream for failover.

type FeatureFlags

type FeatureFlags struct {
	LiveMode    bool `yaml:"live_mode"`
	PremiumGate bool `yaml:"premium_gate"`
}

FeatureFlags controls runtime behavior.

type GuacamoleHandler

type GuacamoleHandler struct {
	// contains filtered or unexported fields
}

func NewGuacamoleHandler

func NewGuacamoleHandler(ws *websocket.Conn, tunnel *guacamole.Tunnel) *GuacamoleHandler

func (GuacamoleHandler) Start

func (r GuacamoleHandler) Start()

func (GuacamoleHandler) Stop

func (r GuacamoleHandler) Stop()

type ModelConfig

type ModelConfig struct {
	// contains filtered or unexported fields
}

ModelConfig is the runtime singleton that serves model routing and pricing from a parsed YAML config file.

func GetModelConfig

func GetModelConfig() *ModelConfig

GetModelConfig returns the singleton. Returns nil if not initialized.

func (*ModelConfig) AutoRoutingActive added in v1.802.0

func (mc *ModelConfig) AutoRoutingActive(orgPref string) bool

AutoRoutingActive decides whether the virtual `auto`/`zen-router` model routes for a request, given the EFFECTIVE preference already resolved by effectiveAutoRouting (org row > "*" GlobalDefaultOwner row > deprecated ROUTER_ENABLED env). Precedence on that resolved three-state preference:

  • "disabled": never routes — `auto` falls through as a pre-routing unknown id
  • "enabled": routes whenever router config is present (per-org or global opt-in)
  • "" (unset): every row and the env are unset — the conf router.enabled flag is the last-resort default

func (*ModelConfig) ChangedAt added in v1.833.72

func (mc *ModelConfig) ChangedAt() time.Time

ChangedAt returns when the routes or prices last changed.

func (*ModelConfig) ConfRouterPolicy added in v1.811.0

func (mc *ModelConfig) ConfRouterPolicy() (map[string][]string, float64)

ConfRouterPolicy returns the live conf router Prefer + CostCeiling under the read lock — the baseline that effectiveRouterPrefer / effectiveRouterCostCeiling fold the per-org OrgSettings over. The Prefer map is copied so callers never hold (or mutate) the live config map.

func (*ModelConfig) ContextWindow added in v1.806.6

func (mc *ModelConfig) ContextWindow(model string) int

ContextWindow returns the max context (tokens) a model is served at, or 0 when nothing declares it (the caller applies the floor).

A window is a property of WHERE a model is served, not of the model alone: GLM-5.2 is a 1M-context model, but DigitalOcean serves it at 262144. So the value resolves in three steps, most specific first:

provider override  (this route's own context_window)
model default      (the upstream leaf's context_window, via the alias chain)
floor              (0 here; model.DefaultContextLength at the call site)

The alias chain means `zen5` inherits its upstream's window without redeclaring it. Lookup is by normalized lowercase key.

func (*ModelConfig) GetPrice

func (mc *ModelConfig) GetPrice(model string) modelPrice

GetPrice returns pricing for a model name, with alias and default fallback.

func (*ModelConfig) GetPriceOK added in v1.812.0

func (mc *ModelConfig) GetPriceOK(model string) (modelPrice, bool)

GetPriceOK is GetPrice plus whether a REAL per-model price was found (true) or the configured default was synthesized (false). The price value is identical to GetPrice; only unpriced-model detection reads the bool.

func (*ModelConfig) LastPricingRefresh

func (mc *ModelConfig) LastPricingRefresh() time.Time

LastPricingRefresh returns when pricing was last refreshed from live source.

func (*ModelConfig) ListModels

func (mc *ModelConfig) ListModels() []modelInfo

ListModels returns visible models sorted by name (excludes hidden).

func (*ModelConfig) ListModelsWithUpstream

func (mc *ModelConfig) ListModelsWithUpstream() []zapModelEntry

func (*ModelConfig) ListRouteProviders added in v1.832.17

func (mc *ModelConfig) ListRouteProviders() []string

ListModelsWithUpstream returns all models including upstream IDs (for ZAP). ListRouteProviders returns the distinct providers behind the LISTED routes. Same hidden-exclusion rule as ListModels, so the two agree by construction.

func (*ModelConfig) MaxOutput added in v1.832.18

func (mc *ModelConfig) MaxOutput(model string) int

MaxOutput returns the most COMPLETION tokens `model` can produce, from models.yaml max_output_tokens, following the alias chain exactly as ContextWindow does (`zen5` inherits its upstream's ceiling without redeclaring it). 0 means the model declares none.

It is the honest ceiling for anyone who must bound a completion BEFORE it runs — a prepaid gate reserving what a call could cost, a client capping its own request. The alternative is a constant, and a constant is wrong per model by construction: it caps a 1M-context model at whatever number was typed, and it is always one release out of date. Same lesson as model.GetContextLength's deleted name-matching table — declare it in models.yaml, resolve it here.

func (*ModelConfig) PremiumGateEnabled

func (mc *ModelConfig) PremiumGateEnabled() bool

PremiumGateEnabled returns whether the premium gate feature is active.

func (*ModelConfig) Reload

func (mc *ModelConfig) Reload() error

Reload re-reads the config file and triggers a live pricing fetch if enabled.

func (*ModelConfig) ResolveRoute

func (mc *ModelConfig) ResolveRoute(model string) *modelRoute

ResolveRoute looks up a user-facing model name and returns its route. Returns nil if the model is not in the routing table.

func (*ModelConfig) RetryConfig added in v1.806.7

func (mc *ModelConfig) RetryConfig() RetryDef

RetryConfig returns the configured retry policy (zero fields mean "use the default"). Read under the lock so a live config reload is safe.

func (*ModelConfig) RouteForContext added in v1.806.7

func (mc *ModelConfig) RouteForContext(model string, tokens int) (provider, upstream string, window int, ok bool)

RouteForContext picks a route for `model` that can actually serve a prompt of `tokens`, returning the provider and upstream to call.

The primary route is used whenever it fits. When it does not — the prompt is 400K and DO serves glm-5.2 at 262144 — the request is not refused: the fallback chain is searched for a provider that serves the SAME model with a window big enough, and that one is called instead. Fallbacks are declared in preference order, so the first that fits wins.

This is why the window lives on the (provider, upstream) pair: it turns the fallback chain from failover-only into capability selection. If nothing in the chain fits, the primary is returned and the upstream rejects it — an honest error from the model rather than a guess from us.

tokens <= 0 means "unknown size": take the primary.

func (*ModelConfig) RouterClient added in v1.802.0

func (mc *ModelConfig) RouterClient(known func(string) bool) router.Client

RouterClient assembles a router.Client from the config, regardless of the enabled flag — the enable decision is made separately by AutoRoutingActive. `known` restricts the choice to models the caller can serve for the current org (typically resolveModelRouteForOrg != nil). Cheap to build per request.

func (*ModelConfig) RouterEnabled added in v1.802.0

func (mc *ModelConfig) RouterEnabled() bool

RouterEnabled reports whether the virtual `auto`/`zen-router` model is active.

func (*ModelConfig) Status

func (mc *ModelConfig) Status() string

Status returns a human-readable status string for diagnostics.

func (*ModelConfig) Stop

func (mc *ModelConfig) Stop()

Stop signals the background refresh goroutine to exit.

type ModelConfigFile

type ModelConfigFile struct {
	Version        int                 `yaml:"version"`
	Services       ServiceEndpoints    `yaml:"services"`
	Cache          CacheTTLs           `yaml:"cache"`
	Features       FeatureFlags        `yaml:"features"`
	Retry          RetryDef            `yaml:"retry"`
	Router         RouterConfigDef     `yaml:"router"`
	DefaultPricing ModelPriceDef       `yaml:"default_pricing"`
	Models         map[string]ModelDef `yaml:"models"`
}

ModelConfigFile is the top-level structure of conf/models.yaml.

type ModelDef

type ModelDef struct {
	Provider     string         `yaml:"provider"`
	Upstream     string         `yaml:"upstream"`
	Fallbacks    []FallbackDef  `yaml:"fallbacks,omitempty"`
	Premium      bool           `yaml:"premium"`
	Hidden       bool           `yaml:"hidden"`
	OwnedBy      string         `yaml:"owned_by"`
	AliasOf      string         `yaml:"alias_of"` // the id this one stands for: not a route, not listed, served and billed as that id
	AliasPricing string         `yaml:"alias_pricing"`
	PricingOnly  bool           `yaml:"pricing_only"`
	Pricing      *ModelPriceDef `yaml:"pricing,omitempty"`
	// ContextWindow is the model's max input+output context in tokens. When
	// set (>0) it overrides the heuristic getContextLength table — models.yaml
	// is the per-model source of truth, configurable without a rebuild. This
	// is the single field that stops long prompts (and /compact) dead-ending
	// on a stale 16K/256K fallback for models the table predates.
	ContextWindow int `yaml:"context_window,omitempty"`
	// MaxOutputTokens is the model's max completion length (tokens), taken from
	// the upstream catalog. Surfaced in /v1/models so a client caps its output
	// request honestly instead of guessing.
	MaxOutputTokens int `yaml:"max_output_tokens,omitempty"`
	// Vision reports the model accepts image input (OpenAI image_url content
	// parts); Tools reports it supports function/tool calling. Both are additive
	// capability flags surfaced in /v1/models (omitempty ⇒ present only when
	// true). Set ONLY from a live capability probe of the serving provider —
	// never guessed — so absence means "not advertised", never a fabricated yes.
	Vision bool `yaml:"vision,omitempty"`
	Tools  bool `yaml:"tools,omitempty"`
	// Outputs are the kinds of answer the model produces, surfaced in /v1/models
	// as `outputs` — "decision" for a model served at /v1/decisions — so a
	// catalog never offers it for a chat turn. Absent ⇒ not advertised.
	Outputs []string `yaml:"outputs,omitempty"`
	// Released is when the model was released, RFC 3339, surfaced in /v1/models as
	// `created`. Absent ⇒ the listing's own time, as for every model whose release
	// nothing here records.
	Released string `yaml:"released,omitempty"`
}

ModelDef describes a single model entry in the config.

type ModelPriceDef

type ModelPriceDef struct {
	InputPerMillion   float64 `yaml:"input_per_million,omitempty"`
	OutputPerMillion  float64 `yaml:"output_per_million,omitempty"`
	Input             float64 `yaml:"input,omitempty"`
	Output            float64 `yaml:"output,omitempty"`
	CostInPerMillion  float64 `yaml:"cost_in_per_million,omitempty"`
	CostOutPerMillion float64 `yaml:"cost_out_per_million,omitempty"`
}

ModelPriceDef holds per-million token economics: the customer price (Input/Output, with the *_per_million long form) plus the optional provider COGS (cost_in_per_million / cost_out_per_million). COGS unset ⇒ cost defaults to price (zero margin), so an entry that lists only a price is byte-identical to before.

type OpenAIResponsesRequest added in v1.806.15

type OpenAIResponsesRequest struct {
	Model             string            `json:"model"`
	Instructions      string            `json:"instructions,omitempty"`
	Input             json.RawMessage   `json:"input"`
	Tools             []responsesTool   `json:"tools,omitempty"`
	ToolChoice        json.RawMessage   `json:"tool_choice,omitempty"`
	ParallelToolCalls *bool             `json:"parallel_tool_calls,omitempty"`
	Stream            bool              `json:"stream,omitempty"`
	MaxOutputTokens   int               `json:"max_output_tokens,omitempty"`
	Temperature       *float32          `json:"temperature,omitempty"`
	TopP              *float32          `json:"top_p,omitempty"`
	Store             bool              `json:"store,omitempty"`
	Metadata          map[string]string `json:"metadata,omitempty"`
	Reasoning         json.RawMessage   `json:"reasoning,omitempty"`
	Text              json.RawMessage   `json:"text,omitempty"`
}

OpenAIResponsesRequest is the subset of POST /v1/responses used by Codex and OpenAI SDKs. Unknown fields are deliberately accepted for forward compatibility; fields that Chat Completions cannot represent are ignored.

type OpenAIWriter

type OpenAIWriter struct {
	Cleaner    Cleaner
	Buffer     []byte
	MessageBuf []byte
	RequestID  string
	Stream     bool
	StreamSent bool
	Model      string
	// IncludeUsage mirrors the request's stream_options.include_usage. Per the
	// OpenAI spec the trailing empty-choices usage chunk is emitted ONLY when the
	// client asks for it; sending it unconditionally breaks clients that read
	// choices[0] on every chunk.
	IncludeUsage bool
	// contains filtered or unexported fields
}

OpenAIWriter turns the upstream's event stream into OpenAI's, and writes the result to `out`.

It is an io.Writer with an io.Writer inside it, and the inner one is a FIELD because the destination is a value the caller chooses, not a place to be reached for. /v1/responses composes its own translating writer here and reads the same chat stream in a second dialect; giving this type an http.ResponseWriter meant that caller had to reach into the request context and swap what it found.

func (*OpenAIWriter) Close

func (w *OpenAIWriter) Close(promptTokens, completionTokens, totalTokens int) error

Close finalizes the stream by sending completion message and DONE marker

func (*OpenAIWriter) Flush added in v1.833.89

func (w *OpenAIWriter) Flush()

Flush pushes what has been written as far as the destination allows, and is what makes the stream a stream: an event that sits in a buffer until the reply ends has been typed, not streamed. Best-effort, like the http.Flusher assertion it replaces — a destination that cannot flush (io.Discard, on the non-streaming path) has nothing to push.

Two shapes, because both are real here: a *bufio.Writer from the stream callback returns an error, and a wrapper that forwards to one may not.

func (*OpenAIWriter) MessageString

func (w *OpenAIWriter) MessageString() string

MessageString returns the complete buffered message

func (*OpenAIWriter) Reset added in v1.833.24

func (w *OpenAIWriter) Reset()

Reset discards what a failed attempt accumulated, so the next provider's answer is not served glued to the dead one's half-sentence.

Write APPENDS to Buffer and MessageBuf, and one writer is shared across every failover attempt. A provider that emitted three tokens and then died leaves those three tokens in the buffer; without this the client is handed them followed by a complete answer from somebody else, which is indistinguishable from a model losing its mind and is not detectable downstream.

StreamSent is NOT cleared. It records that bytes reached the CLIENT, which is a fact about the wire and cannot be undone — it is precisely the flag that forbids the retry this method prepares for.

func (*OpenAIWriter) Write

func (w *OpenAIWriter) Write(p []byte) (n int, err error)

Write processes incoming data chunks and formats them for OpenAI compatibility

type PanelJudge added in v1.826.5

type PanelJudge struct {
	Model  string  `json:"model"`
	Weight float64 `json:"weight"`
	Mean   float64 `json:"mean"`
	N      int     `json:"n"`
}

PanelJudge is one judge's public, in-process snapshot: its model id, current reliability weight, running mean of RAW scores (the judge's own calibration baseline), and how many scores it has observed. Scalars + a model id only — no content, no PII — so it rides the public /v1/ai/router/judge-panel surface the world.hanzo.ai dashboard polls.

func PanelSnapshot added in v1.826.5

func PanelSnapshot() []PanelJudge

PanelSnapshot copies the LIVE MFJP calibration state under the lock into a stable, deterministically-ordered (by model id) slice of per-judge scalars for the read endpoint. Empty when no judge has scored yet ⇒ the endpoint reports available:false.

type Pool added in v1.833.248

type Pool struct {
	State  string
	Keys   int
	Ready  int
	Resets time.Time // when the first account that is out comes back; zero when none is out
}

Pool is the free lane's standing across every vendor account it spends: how many accounts there are, how many take a free request now, and when the first one that does not comes back. It holds no key and no key id.

func FreePool added in v1.833.248

func FreePool() Pool

FreePool is the free pool's standing now, as this process has heard it from the vendor.

It is what the accounts' own answers said, and nothing else: an account is out only after the vendor refused it, and back when the vendor said it would be. So a process that has not yet sent a free request reports every account ready, which is true until the vendor says otherwise.

type ProviderUsage added in v1.809.0

type ProviderUsage struct {
	Provider  string                     `json:"provider"`
	Connected bool                       `json:"connected"`
	Available bool                       `json:"available"`
	Note      string                     `json:"note,omitempty"`
	Currency  string                     `json:"currency"`
	Start     string                     `json:"start"`
	End       string                     `json:"end"`
	Interval  string                     `json:"interval"`
	Totals    ProviderUsageTotals        `json:"totals"`
	Series    []ProviderUsageSeriesPoint `json:"series"`
	ByModel   []ProviderUsageModelSpend  `json:"byModel"`
}

ProviderUsage is the ONE normalized third-party-usage value. Money is USD cents end-to-end (matching CloudUsageOverview.spendCents), so the unified panel renders a connected provider with the SAME vocabulary as native Hanzo usage. `connected` is false when the org has no active connection; `available` is false (with a human `note`) when the provider API returned nothing or the key lacked the usage scope — the two distinct honest-empty states the UI shows instead of a fabricated zero.

type ProviderUsageModelSpend added in v1.809.0

type ProviderUsageModelSpend struct {
	Model      string `json:"model"`
	SpendCents int64  `json:"spendCents"`
	Tokens     int64  `json:"tokens"`
	Requests   int64  `json:"requests"`
}

ProviderUsageModelSpend is one model's slice of the window (spend-by-model). Spend is 0 for providers whose per-model cost is not exposed by their usage API (honest, not fabricated) — tokens/requests are still the real per-model figures.

type ProviderUsageSeriesPoint added in v1.809.0

type ProviderUsageSeriesPoint struct {
	T          string `json:"t"` // RFC3339 bucket start (UTC)
	SpendCents int64  `json:"spendCents"`
	Tokens     int64  `json:"tokens"`
	Requests   int64  `json:"requests"`
}

ProviderUsageSeriesPoint is one day-bucket of the ascending time series.

type ProviderUsageTotals added in v1.809.0

type ProviderUsageTotals struct {
	SpendCents   int64 `json:"spendCents"`
	Tokens       int64 `json:"tokens"`
	InputTokens  int64 `json:"inputTokens"`
	OutputTokens int64 `json:"outputTokens"`
	Requests     int64 `json:"requests"`
}

ProviderUsageTotals are the window totals — the metric cards.

type RefinedWriter

type RefinedWriter struct {
	*bufio.Writer
	// contains filtered or unexported fields
}

func (*RefinedWriter) MessageString

func (w *RefinedWriter) MessageString() string

func (*RefinedWriter) ReasonString

func (w *RefinedWriter) ReasonString() string

func (*RefinedWriter) SearchString

func (w *RefinedWriter) SearchString() string

func (*RefinedWriter) String

func (w *RefinedWriter) String() string

func (*RefinedWriter) ToolString

func (w *RefinedWriter) ToolString() string

func (*RefinedWriter) Write

func (w *RefinedWriter) Write(p []byte) (n int, err error)

type Refusal added in v1.833.251

type Refusal struct {
	Says  string
	Shape any
	Wait  bool
}

Refusal is one status a handler refuses with: what it means to the caller, the body it carries, and whether it asks the caller to wait (Retry-After and Retry-After-Ms).

type Response

type Response struct {
	Status string `json:"status"`
	Msg    string `json:"msg"`
	Code   string `json:"code,omitempty"` // machine name of the failure; clients switch on this, never on Msg
	Data   any    `json:"data"`
	Data2  any    `json:"data2"`
}

type ResponsesCall added in v1.833.232

type ResponsesCall struct {
	Chat []byte
	// contains filtered or unexported fields
}

ResponsesCall is a /v1/responses request read as the chat completion it asks for. Chat is that completion's body; Stream and Whole write its answer back in the Responses dialect. It is the one translation: ai serves Chat itself, and a host that serves chat in-process (cloud's zen) serves it there and answers through the same two functions.

func ReadResponses added in v1.833.232

func ReadResponses(body []byte, encoding string) (*ResponsesCall, error)

ReadResponses reads a Responses body, zstd-compressed when encoding says so. Every error is the caller's; one for a body too large to expand wraps zstd.ErrDecoderSizeExceeded.

func (*ResponsesCall) Stream added in v1.833.232

func (r *ResponsesCall) Stream(w io.Writer) io.WriteCloser

Stream writes a chat SSE stream to w as Responses events, as it is produced.

func (*ResponsesCall) Whole added in v1.833.232

func (r *ResponsesCall) Whole(chat []byte) ([]byte, error)

Whole translates one finished chat completion into a Responses object.

type RetryDef added in v1.806.7

type RetryDef struct {
	Attempts    int    `yaml:"attempts,omitempty"`
	BaseBackoff string `yaml:"base_backoff,omitempty"` // e.g. "500ms"
	MaxBackoff  string `yaml:"max_backoff,omitempty"`  // e.g. "4s"
}

RetryDef is how long we hold a request open for a provider that is merely busy, rather than handing its 429 to the client.

It is configuration, not a constant, for the same reason the context windows are: the right number is a property of the providers we happen to be using today, and it changes without our code changing. Baking it in means a rebuild to tune a timeout — which is how the context table ended up lying for a year.

attempts: total tries of ONE provider (1 disables same-provider retry). base/max: exponential backoff bounds, jittered, capped by the caller's deadline.

type RouterConfigDef added in v1.802.0

type RouterConfigDef struct {
	Enabled     bool                `yaml:"enabled"`
	Endpoint    string              `yaml:"endpoint"`     // zen-router base URL; "" = heuristic only
	Prefer      map[string][]string `yaml:"prefer"`       // task tag → ordered model ids ("default" catch-all)
	CostCeiling float64             `yaml:"cost_ceiling"` // advisory cost cap, USD per 1k tokens (per-1k), forwarded verbatim as the engine SLO

	// Depth names, for a free model id a caller sends by default, the priced SKU a
	// FUNDED caller is served at each reasoning depth: requested id → depth → SKU.
	// Depth keys are the effort words callers send (off, minimal, low, medium, high,
	// xhigh, max) plus "default" for a request that states none. A caller whose plan
	// or bought credit does not fund the priced SKU keeps the free id. See DepthRoute.
	Depth map[string]map[string]string `yaml:"depth"`
}

RouterConfigDef configures the virtual `auto`/`zen-router` model. When disabled (the default) `auto` is not a routable model and behaves like any other unknown id. When enabled, a chat request for `auto` is classified and mapped to a concrete servable model before provider/pricing/billing resolution — so the request bills and reports the model that served it.

type RoutingHost added in v1.833.272

type RoutingHost struct {
	Snapshot func(ctx context.Context) ([]byte, error)
	Apply    func(ctx context.Context, catalog []byte) error
	// Stats is the family's live standing (key balances, the free lane's model
	// health), JSON; nil when the host has none.
	Stats func(ctx context.Context) ([]byte, error)
}

RoutingHost is a family catalog served in this process: its snapshot and the one write path onto it, both in the family's admin JSON. The host sets Zen at mount.

var Zen *RoutingHost

Zen is the zen catalog of this process; nil until the host mounts zen.

type Run added in v1.832.41

type Run struct {
	Org string
	// ID names the run for attribution. It reaches the usage record so one run's
	// spend is a SUM the org can read back, and never a guess.
	ID string
}

Run is what a live run key resolves to: the org that pays, and the run it was minted for. Empty Org is not a run — there is no third answer.

type ServedUsage added in v1.814.0

type ServedUsage struct {
	Owner            string // billing org (who paid) — the warehouse partition key
	User             string // actor, "owner/name" when known
	Model            string // the SKU the caller requested (zen5, …)
	Provider         string // serving family label ("zen")
	RequestID        string
	Status           string // "success" | "error" | "failover" (an arm that failed)
	ErrorMsg         string
	PromptTokens     int // the WHOLE prompt; CachedTokens is a part of it
	CompletionTokens int
	BilledNano       int64 // exact retail billed, nano-USD; 0 = recompute from rates
	CostNano         int64 // exact upstream COGS, nano-USD; 0 = recompute from rates
	StartTime        time.Time

	Served          string        // the arm that generated the answer (gen_ai.response.model)
	Vendor          string        // the provider that ran that arm (gen_ai.provider.name)
	Failover        string        // the arms that failed before it, with why
	CachedTokens    int           // of PromptTokens: served from the upstream's prompt cache
	ReasoningTokens int           // of CompletionTokens: spent reasoning
	First           time.Duration // time from StartTime to the first token of the answer
}

ServedUsage is the trace input for a request that was BILLED ELSEWHERE — a co-resident subsystem that debits commerce itself (zen's Meter in the unified cloud binary) but must still land in the ONE usage warehouse + o11y span plane this package owns. Money is exact nano-USD when the biller knows it (zen computes both retail and upstream COGS per served tier); 0 falls back to the rate-table recompute.

type ServiceEndpoints

type ServiceEndpoints struct {
	PricingURL string `yaml:"pricing_url"`
}

ServiceEndpoints holds URLs for external pricing/model services.

Source Files

Jump to

Keyboard shortcuts

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