Documentation
¶
Overview ¶
Package clients holds the typed inter-subsystem clients used by cloud.Deps.
A dependency resolves to exactly one of two things, and BuildDeps decides which from cfg.Enabled(name) alone:
the CO-RESIDENT implementation, when the subsystem is mounted in this process. Direct Go method calls; no marshalling, no network. The subsystem's own Mount installs it.
Disabled<Subsystem>(): a typed client that fails closed with a clear message. It lets mount code detect "the dep isn't here" without a nil deref, and — the part that matters — it is HONEST about being absent.
There is no third factory, and there used to be ¶
This package also shipped <Subsystem>RPCAt(addr): a "ZAP RPC" client selected by CLOUD_<X>_ZAP_ADDR whose every method returned
cloud: ZAP RPC client for iam@iam.hanzo.svc:9653 not yet wired (zapc-gen pending)
It was scaffolding for a code generator that never landed, and it made the fleet's transport story unfalsifiable. Setting the address logged "deps.IAM → ZAP RPC" at boot and then failed every call, so the one signal an operator had said the wire was up while nothing crossed it. A client that cannot carry a byte is worse than no client, because a missing one is diagnosed in seconds and a lying one is diagnosed in an incident.
The transport for a peer that is NOT in this process is the peer plane: plane.Ask over the peer's own socket, addressed by NAME (see plane/ask.go, and the generated per-app clients under plane/<app>). It needs no endpoint configuration, which is why removing the address knobs removed nothing real. A subsystem with a plane op is reached; one without is disabled and says so.
Index ¶
- Constants
- func AIHTTPAt(baseURL, apiKey, defaultModel string) types.AIClient
- func AIHTTPM2M(baseURL, tokenURL, clientID, clientSecret, defaultModel string) types.AIClient
- func AIHTTPM2MOn(baseURL, tokenURL, clientID, clientSecret, defaultModel string, ...) types.AIClient
- func AIHTTPOn(baseURL, apiKey, defaultModel string, rt http.RoundTripper) types.AIClient
- func DisabledAI() types.AIClient
- func DisabledBase() types.BaseClient
- func DisabledCommerce() types.CommerceClient
- func DisabledIAM() types.IAMClient
- func DisabledKMS() types.KMSClient
- func DisabledMQ() types.MQClient
- func DisabledO11y() types.O11yClient
- func DisabledPayments() types.PaymentsClient
- func DisabledVFS() types.VFSClient
- func DisabledVault() types.VaultClient
- func IsDisabled(err error) bool
- func NewS3VFS(admin s3admin.Admin) (types.VFSClient, error)
- func StartGenAISpan(ctx context.Context, system, operation, model, org, project string) (context.Context, trace.Span)
Constants ¶
const TeamBlobBucket = "team-blobs"
TeamBlobBucket is the single bucket every team blob lands in. Per-tenant isolation is the org-scoped KEY PREFIX (team/blobs/<org>/…) the consumer builds, exactly like clients/s3's per-org physical naming — not a bucket-per-tenant.
Variables ¶
This section is empty.
Functions ¶
func AIHTTPAt ¶ added in v1.786.32
AIHTTPAt returns a types.AIClient that POSTs OpenAI-compatible chat completions to baseURL, authenticated with apiKey. baseURL is the gateway /v1 root (the go-openai client appends /chat/completions). defaultModel is substituted when a ChatRequest carries no explicit model.
apiKey is a KMS-injected secret and is NEVER logged: it lives only inside the go-openai client's Authorization header. Callers log the base URL and default model, never the key.
func AIHTTPM2M ¶ added in v1.786.32
AIHTTPM2M returns a types.AIClient that authenticates to the gateway with an IAM client-credentials (M2M) token instead of a static key. This is the durable Hanzo credential path: the cloud binary mints and auto-refreshes a short-lived token from its OWN service identity (IAM_CLIENT_ID/SECRET), so there is NO static key to rotate and no expiry cliff. On the Hanzo deployment that identity resolves to admin/hanzo-cloud, which the gateway treats as balance-exempt — so cloud's own per-org ResourceMeter stays the single revenue debit (no double-bill).
tokenURL is the IAM token endpoint ({issuer}/v1/iam/oauth/token). clientSecret is a KMS-injected secret and is NEVER logged: it lives only inside the oauth2 token source. The token is fetched lazily on first use (boot never blocks on IAM) and cached+refreshed automatically by the oauth2 client.
go-openai sets its own Authorization header only when its authToken is non-empty; here it is empty, so the sole auth header is the fresh Bearer the oauth2 transport injects on every request.
func AIHTTPM2MOn ¶ added in v1.801.408
func AIHTTPM2MOn(baseURL, tokenURL, clientID, clientSecret, defaultModel string, rt http.RoundTripper) types.AIClient
AIHTTPM2MOn is AIHTTPM2M with the TRANSPORT stated separately from the address, for the same reason AIHTTPOn exists: the inference wire can reach a peer over its own socket instead of the public listener. Only the INFERENCE leg rides rt — the token exchange keeps the default transport, because IAM is a different peer and naming it is a separate question.
func AIHTTPOn ¶ added in v1.801.408
func AIHTTPOn(baseURL, apiKey, defaultModel string, rt http.RoundTripper) types.AIClient
AIHTTPOn is AIHTTPAt with the TRANSPORT stated separately from the address — the same client, the same OpenAI-compatible wire, reached a different way.
It exists because `ai` is a plugin of this same binary running as its own process, and its routes ride its unix socket exactly as they ride the public listener ("ZAP over a unix socket is simply the address the caller dialed"). A sibling can therefore speak the ordinary wire to a peer WITHOUT leaving the host: no ingress, no Cloudflare, no public address, and no token minted to authenticate to our own deployment.
rt nil ⇒ the default transport, so AIHTTPAt is unchanged. When rt dials a fixed socket the base URL's HOST is inert — it names the peer for logs and error text, and the path prefix still matters.
func DisabledBase ¶
func DisabledBase() types.BaseClient
DisabledBase returns a fail-closed Base client.
func DisabledCommerce ¶
func DisabledCommerce() types.CommerceClient
DisabledCommerce returns a fail-closed Commerce client.
func DisabledO11y ¶
func DisabledO11y() types.O11yClient
DisabledO11y returns an O11y client that emits to /dev/null. Used when o11y isn't mounted; subsystems get no-op metrics rather than nil deref or error spam.
func DisabledPayments ¶
func DisabledPayments() types.PaymentsClient
DisabledPayments returns a fail-closed Payments client.
func DisabledVault ¶
func DisabledVault() types.VaultClient
DisabledVault returns a fail-closed Vault client.
func IsDisabled ¶
IsDisabled reports whether err originated from a disabled client. Subsystem mount code can use this to log a friendly warning instead of cascading a 500.
func NewS3VFS ¶ added in v1.786.112
NewS3VFS builds the S3-backed VFSClient from the shared admin config. The S3 client is offline-constructed (no network here); the bucket is created if absent best-effort now AND lazily on the first op (so a boot-time S3 blip self-heals rather than permanently disabling files). Returns an error only if the client cannot be constructed (missing creds / invalid endpoint) — the caller then falls back to DisabledVFS (fail closed).
func StartGenAISpan ¶ added in v1.801.186
func StartGenAISpan(ctx context.Context, system, operation, model, org, project string) (context.Context, trace.Span)
StartGenAISpan opens one OTel gen_ai client span on the shared cloud tracer and stamps the request-side semantic-convention attributes every AI call carries: gen_ai.system (the serving provider — "hanzo" for the Hanzo gateway, "cloudflare" for Workers AI, …), gen_ai.operation.name, gen_ai.request.model, plus the per-tenant scope (hanzo.org / hanzo.project). It is the ONE gen_ai span constructor: the HTTP chat/embed clients here AND any other inference path (the per-org Cloudflare Workers AI proxy) emit to the SAME o11y span plane through it, so AI telemetry is one shape with one tenant-isolation contract, never a parallel per-provider span. The caller defers span.End() and adds response attributes (tokens, status) after the call returns.
Types ¶
This section is empty.