tools

package
v1.801.218 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: Apache-2.0 Imports: 27 Imported by: 0

Documentation

Overview

Package tools is the ONE tool plane for Hanzo Cloud: a single registry where every callable capability — a connector action, a user function, a zap service route, a cloud /v1 control ("full-cloud-control"), an agent, a skill, or a tool on an org's own external MCP server — is a Tool with a Source, a JSON-Schema, a per-(org,project) activation state, and an optional price.

Decomplected on the Rich Hickey seam: a Source knows how to LIST its tools and DISPATCH one; the registry knows nothing about how any single source works. Each source REGISTERS a Provider into the registry from its own Mount — no source duplicates listing or dispatch logic, and the registry never grows a per-source branch. Adding a source is: implement Provider, call tools.Register.

Every dispatch flows through ONE per-principal plane: the caller's VALIDATED org (principal.Org) gates the call, the tool must be ACTIVATED for that (org,project) or the call is 403, a priced tool settles through the explicit x402 Charger seam, and the platform meters one unit. The same isolation boundary the connectors MCP endpoint (clients/automations) already ships — generalized across every source.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotActivated — the tool exists for the scope but is not activated for this
	// (org,project). The activation API (task 5) toggles it on.
	ErrNotActivated = errors.New("tools: not activated for this org/project")
	// ErrUnknownTool — no source offers a tool by this name for the scope.
	ErrUnknownTool = errors.New("tools: unknown tool")
	// ErrNotDispatchable — the tool is discovery/activation-only (e.g. a skill).
	ErrNotDispatchable = errors.New("tools: not dispatchable")
	// ErrPaymentRequired — a priced tool could not be settled through the Charger.
	ErrPaymentRequired = errors.New("tools: payment required")
	// ErrChargerUnset — a priced tool was called but no x402 Charger is wired; the
	// call fails CLOSED (a paid tool is never served free).
	ErrChargerUnset = errors.New("tools: payment seam not configured")
)

Sentinel dispatch outcomes. The HTTP layer maps these to status codes: a not-activated tool is 403 (the tool plane never serves an unactivated tool), an unknown tool is 404-in-JSON-RPC, payment-required is 402, not-dispatchable is 422.

Functions

func Mount

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

Mount registers the tool plane on app.

func Register

func Register(p Provider)

Register adds a source Provider to the process-wide registry. Each source calls this ONCE from its Mount (only enabled subsystems mount, so a disabled source is simply absent). Order does not matter: List/Dispatch run at request time.

func SetCharger

func SetCharger(c Charger)

SetCharger installs the x402 payment seam on the process-wide registry. The x402 wiring team calls this once; until it does, priced tools fail closed.

func SetPricer

func SetPricer(p Pricer)

SetPricer installs the marketplace price seam on the process-wide registry.

func Shutdown

func Shutdown(_ context.Context) error

Shutdown closes the stores. Idempotent.

Types

type ActivationStore

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

ActivationStore is the per-(org,project,tool) activation plane: the durable toggle hanzo.chat / hanzo.app read to decide which skills/plugins/connectors an org has turned on. It is the tool-plane twin of the entitlements (org,product) enablement store — a row exists iff the tool is EXPLICITLY activated for that scope, and dispatch fails closed (403) on any tool without one.

Isolation is the (org, project, tool) composite key plus a mandatory `WHERE org=? AND project=?` on every statement. org/project are the VALIDATED principal values, never client input. One SQLite file (all orgs, org column), MaxOpenConns(1), WAL — the shared cloud store discipline.

func OpenActivationStore

func OpenActivationStore(path string) (*ActivationStore, error)

OpenActivationStore opens (and migrates) the activation store at path.

func (*ActivationStore) Activate

func (s *ActivationStore) Activate(ctx context.Context, org, project, tool string, source Source, byUser string) error

Activate turns a tool on for (org, project). Idempotent on the composite key. source + byUser are recorded for the audit/console view.

func (*ActivationStore) Close

func (s *ActivationStore) Close() error

Close closes the underlying database.

func (*ActivationStore) Deactivate

func (s *ActivationStore) Deactivate(ctx context.Context, org, project, tool string) error

Deactivate turns a tool off for (org, project). Idempotent (no row ⇒ no-op).

func (*ActivationStore) IsActivated

func (s *ActivationStore) IsActivated(ctx context.Context, org, project, tool string) bool

IsActivated reports whether tool is activated for (org, project). It is nil-safe: a nil store (pre-Mount / split deploy) reports NOT activated, so dispatch fails closed rather than serving an unactivated tool.

func (*ActivationStore) List

func (s *ActivationStore) List(ctx context.Context, org, project string) ([]string, error)

List returns the activated tool names for (org, project), sorted.

type Charge

type Charge struct {
	Payer     string // paying org's billing ledger (principal Owner/Org).
	Project   string
	Tool      string
	Recipient string // seller payout wallet (Tool.Price.Recipient).
	Currency  string
	Cents     int64
	RequestID string
}

Charge is one settlement request for a monetized tool call. It is the whole contract the registry hands the x402 seam: who pays, who is paid, how much.

type Charger

type Charger interface {
	Charge(ctx context.Context, ch Charge) error
}

Charger settles a monetized tool call over the x402 payment rail (LP-3028, clients/commerce/payment/x402). A SEPARATE team owns the concrete implementation backed by x402.Facilitator.Settle (Payee = the recipient wallet address); the registry codes to THIS narrow interface and keeps the seam explicit so it never pulls the processor/MPC/chain graph into the tool plane. A nil Charger makes every priced tool fail closed (ErrChargerUnset) — a paid tool is never free.

Charge returns nil on a settled payment, ErrPaymentRequired when the payer cannot pay, or another error (fail-closed) on an unavailable rail.

type MCPServer

type MCPServer struct {
	ID         string `json:"id"`
	Org        string `json:"org"`
	Name       string `json:"name"`
	URL        string `json:"url"`
	AuthHeader string `json:"authHeader,omitempty"` // header to inject the KMS secret into (e.g. "Authorization").
	HasSecret  bool   `json:"hasSecret"`
	CreatedAt  int64  `json:"createdAt"`
}

MCPServer is one org-registered external MCP server. AuthHeader/HasSecret record how to authenticate; the secret itself is in KMS at authRef(org, id).

type MCPServerStore

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

MCPServerStore is the per-org registry of external MCP servers (one SQLite file, org column, the shared cloud store discipline). Isolation is a mandatory `WHERE org=?` on every statement; org is the validated principal value.

func OpenMCPServerStore

func OpenMCPServerStore(path string) (*MCPServerStore, error)

OpenMCPServerStore opens (and migrates) the external-server store at path.

func (*MCPServerStore) Close

func (s *MCPServerStore) Close() error

Close closes the underlying database.

func (*MCPServerStore) Create

func (s *MCPServerStore) Create(ctx context.Context, srv MCPServer) (MCPServer, error)

Create inserts a server row (id generated). It does NOT touch KMS — the handler stores the secret first, then records has_secret here.

func (*MCPServerStore) Delete

func (s *MCPServerStore) Delete(ctx context.Context, org, id string) (bool, error)

Delete removes a server for (org, id). Returns whether a row was removed.

func (*MCPServerStore) Get

func (s *MCPServerStore) Get(ctx context.Context, org, id string) (MCPServer, error)

Get returns one server for (org, id).

func (*MCPServerStore) List

func (s *MCPServerStore) List(ctx context.Context, org string) ([]MCPServer, error)

List returns an org's registered servers, sorted by name.

type Price

type Price struct {
	AmountCents int64  `json:"amountCents"`
	Currency    string `json:"currency"`  // ISO 4217, e.g. "USD"; empty ⇒ "USD".
	Recipient   string `json:"recipient"` // payout wallet ref for the marketplace seller.
}

Price declares what a monetized tool call costs and who is paid. Enforcement is the x402 Charger seam (registry.go) — this is only the DECLARATION a marketplace listing carries. A nil Price means the tool is free (no x402 settlement).

type Pricer

type Pricer interface {
	PriceFor(ctx context.Context, scope Scope, tool string) *Price
}

Pricer resolves the marketplace price of a tool at dispatch time. It is the seam the marketplace fills so a monetized listing's price + recipient wallet reach the per-call enforcement path WITHOUT the tool plane importing the marketplace. A tool whose provider already set an intrinsic Price does not consult the Pricer.

type Principal

type Principal struct {
	Org     string
	Project string
	User    string
	Owner   string
	IsAdmin bool
	// contains filtered or unexported fields
}

Principal is the VALIDATED caller a dispatch runs as — resolved once from the request and threaded to every source. Org/Project/User/Owner/IsAdmin are the IAM-native identity; credential is the caller's OWN credential headers, replayed by a builtin tool so a /v1 route runs under the SAME IAM check as a direct HTTP call (cloud's SanitizeIdentity strips minted headers on ingress and re-mints them ONLY from a re-validated credential, so replaying the credential — never the minted headers — is the one way an in-process call carries the caller's identity; this is exactly the zapface in-process-dispatch contract).

func PrincipalFrom

func PrincipalFrom(c *zip.Ctx) (Principal, bool)

PrincipalFrom resolves the validated caller from a request context. It returns ok=false (the caller must answer 403) unless a validated principal carries a non-empty org — the SAME gate principal.Org enforces. Because c.User() is set ONLY from a re-validated credential, a successful resolve guarantees a replayable credential is present; it is captured so a builtin tool can act as this exact caller and never escalate.

type Provider

type Provider interface {
	// Source is the provider's source tag (a provider serves exactly one source).
	Source() Source
	// List returns the tools this source offers for scope. It is scope-aware:
	// a connector source lists an org's connected connectors; the external-MCP
	// source lists tools from the org's registered servers; builtin lists routes.
	List(ctx context.Context, scope Scope) ([]Tool, error)
	// Dispatch invokes the named tool with JSON args, bound to the principal, and
	// returns the JSON-encodable result. A source that only lists (skills) returns
	// ErrNotDispatchable.
	Dispatch(ctx context.Context, p Principal, name string, args map[string]any) (any, error)
}

Provider is one tool SOURCE. It lists the tools it offers to a (org,project) and dispatches a call to one of them bound to the principal. The registry composes providers; it never learns how any single source lists or runs its tools. A source implements this once and calls Register — that is the whole contract.

type Registry

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

Registry is THE tool plane: the set of registered source Providers, the shared per-(org,project) activation store, and the x402 Charger seam. It composes providers and enforces the ONE dispatch policy (activation gate → price gate → dispatch); it knows nothing about how any source lists or runs a tool.

func Default

func Default() *Registry

Default returns the process-wide registry (for marketplace + the HTTP surface).

func NewRegistry

func NewRegistry() *Registry

NewRegistry builds an empty registry. The process-wide one is std (see Default); tests build their own with fake providers.

func (*Registry) Activate

func (r *Registry) Activate(ctx context.Context, org, project, tool, byUser string) error

Activate turns a tool on for (org, project), recording its resolved source. This is the ONE activation write the marketplace "install" and the /v1/tools/activation API both drive, so activation is one store reached one way.

func (*Registry) Activated

func (r *Registry) Activated(ctx context.Context, org, project string) ([]string, error)

Activated returns the activated tool names for (org, project).

func (*Registry) Deactivate

func (r *Registry) Deactivate(ctx context.Context, org, project, tool string) error

Deactivate turns a tool off for (org, project).

func (*Registry) Dispatch

func (r *Registry) Dispatch(ctx context.Context, p Principal, name string, args map[string]any) (any, error)

Dispatch is the ONE per-principal dispatch path, enforcing the ONE policy:

  1. resolve the winning tool (precedence) — ErrUnknownTool if none.
  2. ACTIVATION gate — the tool MUST be activated for (org,project) or ErrNotActivated (403).
  3. PRICE gate — a priced tool settles through the x402 Charger seam or fails closed (ErrChargerUnset / ErrPaymentRequired). A paid tool is never free.
  4. dispatch to the winning source's provider, bound to the principal.

The scope is the principal's own (org, project) — a caller can only ever dispatch its own tools. Metering + audit are the HTTP layer's job (one unit per call).

func (*Registry) Exists

func (r *Registry) Exists(ctx context.Context, scope Scope, name string) bool

Exists reports whether any source offers a tool by name to scope. Used by the marketplace to refuse a phantom listing/install.

func (*Registry) List

func (r *Registry) List(ctx context.Context, scope Scope) []Tool

List returns every tool offered to scope, deduped by name under source precedence (the lowest-rank source wins a collision), sorted by name. Each tool's Activated flag is filled from the activation store. A provider that errors is skipped (its tools are simply absent) — one failing source never blanks the whole plane.

func (*Registry) Register

func (r *Registry) Register(p Provider)

Register adds a provider. Duplicate sources are allowed (each lists its own tools); precedence resolves any name collision across sources.

func (*Registry) SetActivation

func (r *Registry) SetActivation(a *ActivationStore)

SetActivation installs the activation store (called by tools.Mount once DataDir is known). A nil store fails every dispatch closed (nothing is activated).

func (*Registry) SetCharger

func (r *Registry) SetCharger(c Charger)

SetCharger installs the payment seam.

func (*Registry) SetPricer

func (r *Registry) SetPricer(p Pricer)

SetPricer installs the marketplace price seam.

type Scope

type Scope struct {
	Org     string
	Project string
}

Scope is the (org, project) a listing is resolved for. project == "" or the literal default project both denote the org's default scope.

type Source

type Source string

Source names WHERE a tool comes from. It is the ONE dimension precedence and activation-default policy key on, so it is a closed set of values, not free text.

const (
	// SourceBuiltin is a cloud /v1 route exposed as a tool ("full-cloud-control"):
	// a per-user token does over MCP exactly what that user may do over HTTP, gated
	// by the SAME IAM check because dispatch replays the request in-process.
	SourceBuiltin Source = "builtin"
	// SourceConnector is a connector action from clients/automations.
	SourceConnector Source = "connector"
	// SourceFunction is a user-defined function from clients/functions.
	SourceFunction Source = "function"
	// SourceZAPService is a zap-proto service route (tunneled over /zap).
	SourceZAPService Source = "zap-service"
	// SourceAgent is an org agent from clients/agents, callable as a tool.
	SourceAgent Source = "agent"
	// SourceSkill is an agent skill (clients/agentskills): discovery + activation
	// metadata, attached to agents rather than called directly.
	SourceSkill Source = "skill"
	// SourceMCP is a tool on an org's own registered EXTERNAL MCP server.
	SourceMCP Source = "mcp"
)

type Tool

type Tool struct {
	Name         string          `json:"name"`
	Source       Source          `json:"source"`
	Description  string          `json:"description"`
	Schema       json.RawMessage `json:"inputSchema,omitempty"`
	Price        *Price          `json:"price,omitempty"`
	Dispatchable bool            `json:"dispatchable"`
	// Activated is filled by the registry from the activation store for the
	// requesting (org,project); providers leave it zero.
	Activated bool `json:"activated"`
}

Tool is the ONE description of a callable capability, uniform across sources. Schema is the JSON-Schema of the call arguments (MCP inputSchema); Dispatchable is false for a listing-only entry (a skill is activated + attached, not called).

Jump to

Keyboard shortcuts

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