agents

package
v1.801.79 Latest Latest
Warning

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

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

Documentation

Overview

Package agents mounts the Hanzo Cloud /v1/agents surface: per-org autonomous agent definitions and their runs. An agent is a model + a system prompt (instructions) + a set of tool names; running one executes a real chat completion through the in-process AI client (the SAME gateway path the rest of the console uses) and records the run. Tenant isolation is the gateway-minted X-Org-Id (HIP-0026) enforced as the org column on every query, so one tenant can never read, run, or delete another's agents.

Surface (all org-scoped; console's AgentsModule reads {agents:[...]}):

GET    /v1/agents               list agents for the org      -> {agents:[...]}
POST   /v1/agents               create an agent              -> Agent
GET    /v1/agents/:ref          agent detail + recent runs   -> AgentDetail
PATCH  /v1/agents/:ref          update an agent              -> Agent
DELETE /v1/agents/:ref          delete an agent (+ its runs)
POST   /v1/agents/:ref/run      run the agent {input}        -> RunResult
GET    /v1/agents/:ref/runs     run history                  -> {runs:[...]}

:ref is either the agent's public id (the `agent_...` handle create and list return) OR its org-unique name — resolved by Store.Resolve, so a created agent is immediately gettable and runnable by whatever create/list handed back.

The store is SQLite in deps.DataDir (Base/SQLite-only). It holds definitions and run I/O only — never a secret; tool credentials live in KMS by reference.

Index

Constants

View Source
const (
	KindMessage  = "message"
	KindToolCall = "tool-call"
	KindSpawn    = "spawn"
	KindLog      = "log"
	KindStatus   = "status"
	KindControl  = "control"
)

Event kinds — the closed vocabulary of a session's ordered log.

View Source
const (
	CmdPause   = "pause"
	CmdResume  = "resume"
	CmdStop    = "stop"
	CmdMessage = "message"
)

Control commands — the closed vocabulary of remote steering.

View Source
const (
	StatusRunning = "running"
	StatusPaused  = "paused"
	StatusDone    = "done"
	StatusError   = "error"
)

Session status values. running/paused are live; done/error are terminal.

View Source
const (
	ModeOneShot     = "one-shot"
	ModeLongRunning = "long-running"
)

Execution modes. One-shot agents run only on an explicit POST; long-running agents are additionally invoked by the scheduler on their Schedule.

View Source
const (
	TargetLaptop  = "laptop"
	TargetCloud   = "cloud"
	TargetGPU     = "gpu"
	TargetCluster = "cluster"
	TargetMachine = "machine"
)

Target kinds — the closed vocabulary of dispatch destinations.

View Source
const (
	TargetOnline   = "online"
	TargetOffline  = "offline"
	TargetDraining = "draining"
)

Target status — a registered target is online until marked otherwise.

Variables

This section is empty.

Functions

func BillingActor added in v1.801.23

func BillingActor(org, sub string) string

BillingActor is the exported form of the actor identity a session is recorded under. The login-manager adapter (the only external caller) uses it to scope a session stop/count to the REVOKING user's own actor, so a revoke can never reach a co-tenant's sessions. It mirrors what sessions.go stamps on Session.Actor, so a stop's actor predicate matches exactly the sessions that user created.

func CloseSession added in v1.801.23

func CloseSession(ctx context.Context, org, sessionID, status string) error

CloseSession moves an org's session to a terminal state (done|error), stamping ended_at, and publishes the update. The store's monotonic-terminal rule already forbids reopening a finished run; here we only ever set a terminal status, so a double-close is a harmless no-op on an already-terminal row.

func CountActiveSessions added in v1.801.23

func CountActiveSessions(ctx context.Context, org string, m SessionMatch) (int, error)

CountActiveSessions returns how many of org's sessions matching m are live (running|paused) — the device view's "active sessions". Org-scoped; 0 when not mounted or the match is empty.

func LogSessionEvent added in v1.801.23

func LogSessionEvent(ctx context.Context, org, sessionID, kind, actor string, payload []byte) error

LogSessionEvent appends one ordered event (message|tool-call|spawn|log|status| control) to an org's session and fans it out live. The (org, id) pair is re-resolved so a caller can only write to a session THIS org owns; kind is validated against the closed vocabulary and payload is size-bounded + must be well-formed JSON (nil payload is allowed for a bare marker). actor falls back to the org.

func Mount

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

Mount wires the agents surface onto app per HIP-0106.

func OfferRoutedRun added in v1.801.79

func OfferRoutedRun(run RoutedRun) *offer

OfferRoutedRun is the exported seam the coding delivery activity uses to place a run into the live rendezvous. Kept here (agents owns targets + sessions) so the machine-facing HTTP surface and the durable activity share ONE mailbox.

func OpenSession added in v1.801.23

func OpenSession(ctx context.Context, org, actor, agent, title string) (string, error)

OpenSession registers a LIVE root session for org attributed to actor (an "org/sub" identity or a bare label) with the given agent label + title, and returns its id. The session is born running (not terminal like openRunSession's completed one-shot) so a long job streams status/log/tool-call events into it until CloseSession moves it to a terminal state. Best-effort live fan-out (publish) rides the bus; the store row is the truth.

func OpenSessionOn added in v1.801.79

func OpenSessionOn(ctx context.Context, org, actor, agent, title, target string) (string, error)

OpenSessionOn is OpenSession with the run's dispatch TARGET recorded, so mission-control shows a routed run on the machine it was sent to (session.target == the target id) exactly as a locally-linked run shows its host. The target is re-resolved org-scoped and MUST belong to this org — a session can never claim to run on another tenant's machine (the same fail-closed rule sessionContext enforces on the HTTP register path). An empty target falls back to OpenSession.

func Shutdown

func Shutdown(ctx context.Context) error

Shutdown stops the scheduler (draining in-flight runs, bounded by ctx) and closes the agents store. Idempotent — safe to call when nothing is mounted.

func StopSessions added in v1.801.23

func StopSessions(ctx context.Context, org string, m SessionMatch) (int, error)

StopSessions closes every RUNNING|PAUSED session of org matching m — recording a control "stop" event on each and transitioning it to a terminal state — and returns how many it stopped. It is the action a login-out (link revoke) takes so the sessions that ran under a revoked account/device are torn down. Org AND Actor scope it: the caller passes their own actor (org/user), so a revoke can only ever stop the caller's OWN sessions — never a co-tenant's, never an org's every session — even though m's Host/Provider/Account come from an attacker-controllable link row. A match with no actor stops nothing (fail-closed). Not-mounted → (0, nil), so a revoke tolerates a deployment with no session plane.

func TargetDispatchable added in v1.801.79

func TargetDispatchable(ctx context.Context, org, targetID string) error

TargetDispatchable is the exported gate the coding dispatcher injects (it never imports the store directly). Returns nil when a run may be routed to (org, targetID), else a descriptive error.

Types

type Agent

type Agent struct {
	ID               string
	Org              string
	Name             string
	Model            string
	Instructions     string
	Description      string
	Tools            []string
	Status           string
	ExecutionMode    string
	Schedule         string
	ComputeRef       string
	ServiceAccountID string
	CreatedAt        int64
	UpdatedAt        int64
}

Agent is the org-scoped definition of an autonomous worker: a model, a system prompt (instructions), and a set of tool names it may call. Tenant isolation is the org column, enforced on every query. It never stores a secret — tool credentials live in KMS and are referenced by name at run time.

The bot-lifecycle fields promote an agent from a one-shot callable into a long-running bot (per hanzo-agent-bot-architecture: "Bot = Agent + compute + long-running"):

  • ExecutionMode: "one-shot" (default; runs only when POSTed) or "long-running" (the scheduler invokes it on Schedule).
  • Schedule: a 5-field cron expression; required when long-running, ignored otherwise. The scheduler evaluates it once a minute.
  • ComputeRef: an optional visor machine id the bot is bound to. It is an opaque reference here; binding/lifecycle is owned elsewhere.
  • ServiceAccountID: an optional IAM agent service-account (<org>-<agent>). When set it is the Actor recorded on scheduled-run billing so an autonomous run is attributable to a principal, not just the org.

func ListForOrg added in v1.786.112

func ListForOrg(ctx context.Context, org string) ([]Agent, error)

ListForOrg returns the org's agents from the in-process store — the ONE exported seam other in-process subsystems use to read the canonical agent registry WITHOUT an HTTP hop back through the gateway.

It is the decompleced replacement for the old bots-as-members path, which enumerated agents over HTTP (/v1/agents with a forwarded bearer) and broke when HANZO_API_KEY was rejected (bot_members=0). clients/team calls this directly to project each agent as a workspace Employee.

ISOLATION: org is the ONLY tenant key and is used VERBATIM (Store.List filters WHERE org=?), so a caller for org A can never enumerate org B's agents. The caller MUST pass an org it already validated (principal.Org / a verified token claim), never a raw client header. Fails closed (nil, error) when the agents subsystem is not mounted or the org is empty/oversized.

type Event added in v1.786.32

type Event struct {
	ID        string
	SessionID string
	Org       string
	Seq       int64
	Kind      string // message|tool-call|spawn|log|status|control
	Actor     string
	Payload   string // opaque JSON blob (validated well-formed, size-bounded)
	CreatedAt int64
}

Event is one entry in a session's ordered log: a model message, a tool call, a subagent spawn, a free log line, a status change, or a control command the running surface consumes. Seq is monotonic PER SESSION so a subscriber can resume from its last-seen point; Org is denormalised so every read stays org-scoped without a join back to the session row.

type GPU added in v1.801.23

type GPU struct {
	Vendor string `json:"vendor,omitempty"` // nvidia | amd | apple | intel | ...
	Model  string `json:"model,omitempty"`  // "GB10", "8060S", "RTX 4090"
	Memory int64  `json:"memory,omitempty"` // VRAM bytes, 0 = unknown
}

GPU is one accelerator on a machine.

type Metrics added in v1.801.23

type Metrics struct {
	Load1   float64 `json:"load1,omitempty"`
	Load5   float64 `json:"load5,omitempty"`
	Load15  float64 `json:"load15,omitempty"`
	MemUsed int64   `json:"memUsed,omitempty"` // bytes
	MemFree int64   `json:"memFree,omitempty"` // bytes
	GPUUtil float64 `json:"gpuUtil,omitempty"` // 0..1 aggregate utilization
	At      int64   `json:"at,omitempty"`      // unix seconds, server-stamped
}

Metrics is a machine's live state from the last heartbeat.

func (Metrics) IsZero added in v1.801.23

func (m Metrics) IsZero() bool

IsZero reports an all-empty metrics sample.

func (Metrics) Sanitize added in v1.801.23

func (m Metrics) Sanitize() Metrics

Sanitize coerces a metrics sample into a safe, finite range. It does NOT set At — the server stamps that so a client can never backdate or forge the staleness clock.

type RoutedResult added in v1.801.79

type RoutedResult struct {
	OK        bool   `json:"ok"`
	Changed   bool   `json:"changed"`
	Branch    string `json:"branch,omitempty"`
	CommitSha string `json:"commitSha,omitempty"`
	Diffstat  string `json:"diffstat,omitempty"`
	Error     string `json:"error,omitempty"`
}

RoutedResult is a routed run's terminal outcome, reported by the machine and returned to the durable activity so the workflow completes.

type RoutedRun added in v1.801.79

type RoutedRun struct {
	Org            string `json:"org"`
	TargetID       string `json:"targetId"`
	SessionID      string `json:"sessionId"` // the live session opened at dispatch; the machine streams into it
	Repo           string `json:"repo"`
	Project        string `json:"project,omitempty"`
	Base           string `json:"base,omitempty"`
	Branch         string `json:"branch"`
	Prompt         string `json:"prompt"`
	CloneURL       string `json:"cloneUrl"`
	TimeoutSeconds int    `json:"timeoutSeconds,omitempty"`
}

RoutedRun is the NON-SECRET spec of one coding run dispatched to a target. It carries no credential by design: the executing machine authenticates git + model routing with its OWN already-held credentials (the same ones `hanzo code` uses), so no secret ever enters the durable store or crosses to the machine in the claim response. Everything here is safe to persist in the tasks engine.

type Run

type Run struct {
	ID         string
	Org        string
	AgentName  string
	Status     string
	Model      string
	Input      string
	Output     string
	Error      string
	DurationMs int64
	CreatedAt  int64
}

Run is one execution of an agent: the input, the produced output (or error), which model served it, and how long it took. Real history — every row is a call that actually happened.

func RunOnBehalf added in v1.786.82

func RunOnBehalf(ctx context.Context, org, userSub, ref, input string) (Run, error)

RunOnBehalf runs agent `ref` for `org` ON BEHALF OF `userSub`, IN-PROCESS — no gateway hop, no Cloudflare/IPv6 exposure. It is the clean in-process twin of the HTTP s.run handler: the CALLER (e.g. the Slack integrations bridge) has ALREADY authenticated org+userSub server-side, so this entry takes them DIRECTLY and never reads an HTTP principal / JWT / zip.Ctx. It resolves the agent org-scoped, runs it through the SAME runAgent → executeRun → meter path as s.run (one run path: one balance gate, one debit, one recorded run, one live session), and bills billingActor(org, userSub) against ORG's ledger.

ISOLATION: org is the ONLY tenant key. Store.Resolve is org-scoped, so a caller for org A can never resolve, run, or bill against org B's agent — exactly the property the HTTP handler relies on the gateway-minted X-Org-Id for.

A non-nil error means NO run happened: not mounted, invalid org, oversized input, inference not configured, agent-not-found (errNotFound), or a balance-gate denial (out-of-funds / commerce-unknown). A run that executed but whose model failed returns a recorded error-status Run and a nil error.

type Session added in v1.786.32

type Session struct {
	ID        string
	Org       string
	Agent     string // agent name / type label (need not be a cloud Agent row)
	Actor     string // the principal that started it (validated user, or a bound SA)
	Status    string // running|paused|done|error
	ParentID  string // "" for a root (the outer agent)
	RootID    string // the tree key; == ID for a root
	Title     string
	StartedAt int64
	EndedAt   int64 // 0 until a terminal status is reached
	CreatedAt int64
	UpdatedAt int64

	// TaskWorkflowID / TaskRunID link this session to the hanzoai/tasks durable
	// workflow that actually EXECUTES it. This registry is the view/control/stream
	// layer; durable execution (retries, resumability, scheduling) is owned by
	// hanzoai/tasks — NOT by a bespoke scheduler here. A root session maps to a
	// tasks workflow (ExecuteWorkflow); a subagent maps to a child workflow keyed
	// by the same RootID. When these are set, control (pause/resume/stop/message)
	// forwards to the tasks Signal/Cancel API (see State.tasks). Empty = a surface
	// that consumes control from the event stream instead (today's @hanzo/dev).
	TaskWorkflowID string
	TaskRunID      string

	// Execution context — WHERE this session runs. All optional (a surface that
	// doesn't know sets ""), surfaced by mission-control so a card shows the
	// machine/repo/cwd it runs on and the devices view maps "which sessions run
	// where". Host is the machine label; Repo/Cwd are the code context; Target is a
	// registered run-target id (the #48 dispatch association — resolved same-org at
	// register/patch so it never points across tenants). Truth the SURFACE reports.
	Host   string
	Cwd    string
	Repo   string
	Target string

	// Provider/Account tag a session with the linked AI account it ran under (the
	// login-manager tie-in): which provider (claude|codex|hanzo|…) and which
	// subscription/api account served this run. Optional (a surface that doesn't
	// know sets ""), surfaced so the cockpit shows "this ran on your Claude Max
	// acct" and so a login-out (link revoke) can stop the sessions that used it.
	Provider string
	Account  string
}

A live agent-session is a running invocation — a cloud agent run, a bot loop, or a @hanzo/dev CLI run spawning subagents. The SUBAGENT TREE is sessions linked by ParentID: the outer agent is the root (ParentID==""), each spawned subagent is a child, and RootID is the tree key every node in one flow shares. It is the first-class, streamable form of the blue/red/cto fan-out tree.

A session is NOT foreign-keyed to an agents row: an external surface (the @hanzo/dev CLI) registers a session whose Agent is just a label, not a cloud Agent definition. Tenant isolation is the Org column, enforced on every query exactly like agents/runs — one file (agents.db), tenancy is the org.

type SessionFilter added in v1.786.32

type SessionFilter struct {
	Root   string
	Parent string
	Status string
	Limit  int
}

SessionFilter selects a slice of an org's sessions. The fields are AND-ed; a zero field is "any". Scope picks the structural axis:

  • Root set -> every session in that tree (root_id == Root).
  • Parent set -> the direct children of Parent (parent_id == Parent).
  • neither -> roots only (parent_id == ”), the outer-agent view.

type SessionMatch added in v1.801.23

type SessionMatch struct {
	Actor    string
	Host     string
	Provider string
	Account  string
}

SessionMatch selects live (running|paused) sessions to stop or count. Actor (the owning subject, org/user) is MANDATORY and always ANDed, so a match can only ever affect the caller's OWN sessions — never a co-tenant's. Host/Provider/Account are optional narrowing WITHIN the actor's sessions (empty = any of the actor's). A match with no actor selects NOTHING (fail-closed), so a login-out can never sweep another user's — or an org's every — session, even when Host/Provider/Account are attacker-set at link upsert.

type Spec added in v1.801.23

type Spec struct {
	OS     string `json:"os,omitempty"`     // linux | darwin | windows
	Arch   string `json:"arch,omitempty"`   // amd64 | arm64 | ...
	CPUs   int    `json:"cpus,omitempty"`   // logical cores
	Memory int64  `json:"memory,omitempty"` // total RAM, bytes
	GPUs   []GPU  `json:"gpus,omitempty"`
}

Spec is a machine's static capability.

func (Spec) IsZero added in v1.801.23

func (s Spec) IsZero() bool

IsZero reports an all-empty spec (nothing worth storing).

func (Spec) Sanitize added in v1.801.23

func (s Spec) Sanitize() Spec

Sanitize bounds every field so a target row stays small and well-formed no matter what a client sends: strings trimmed + length-capped, counts/sizes non-negative and clamped, GPU list truncated, floats coerced finite. It is total (never errors) so the write path can always proceed with a safe value.

type Store

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

Store is the agents database. ONE SQLite file ({DataDir}/agents.db) holds every org's records; tenancy is the org column.

func (*Store) AppendEvent added in v1.786.32

func (s *Store) AppendEvent(ctx context.Context, e Event) (Event, error)

AppendEvent inserts one event, allocating the next per-session Seq. The store runs on a single connection (SetMaxOpenConns(1)) so the read-then-write of the max seq is serialised; the UNIQUE(session_id,seq) index is the final backstop. The session's updated_at is bumped in the SAME transaction so "last activity" stays truthful. Returns the persisted event (with Seq/CreatedAt) for streaming.

func (*Store) ClaimKeyHash added in v1.801.79

func (s *Store) ClaimKeyHash(ctx context.Context, org, targetID string) (hash string, servingAt int64, err error)

ClaimKeyHash returns a target's stored hash + last serving stamp, or errNoClaimKey when none was ever minted.

func (*Store) Close

func (s *Store) Close() error

func (*Store) CountChildren added in v1.786.32

func (s *Store) CountChildren(ctx context.Context, org, id string) (int, error)

CountChildren returns how many DIRECT children a session has (its fan-out).

func (*Store) CountEvents added in v1.786.32

func (s *Store) CountEvents(ctx context.Context, org, sessionID string) (int, error)

CountEvents returns how many events a session has (the list rollup).

func (*Store) CountLongRunning added in v1.786.32

func (s *Store) CountLongRunning(ctx context.Context, org string) (int, error)

CountLongRunning returns how many scheduled long-running agents an org has — used to cap an org's scheduler footprint at create time.

func (*Store) CountRuns

func (s *Store) CountRuns(ctx context.Context, org, agent string) (int, error)

CountRuns returns how many runs an org's agent has (for the list rollup).

func (*Store) Create

func (s *Store) Create(ctx context.Context, a Agent) error

Create inserts one agent. A UNIQUE(org,name) violation surfaces as errConflict.

func (*Store) CreateSession added in v1.786.32

func (s *Store) CreateSession(ctx context.Context, x Session) error

CreateSession inserts one session. When ParentID is set it MUST reference an existing session IN THE SAME ORG — the caller resolves it via GetSession first so a cross-tenant or dangling parent can never link a tree. RootID is derived by the caller (parent's root, or self for a root); this method persists what it is given after a final same-org sanity check on the parent.

func (*Store) CreateTarget added in v1.801.23

func (s *Store) CreateTarget(ctx context.Context, t Target) error

CreateTarget inserts one target. The id is caller-generated (genID("tgt")).

func (*Store) Delete

func (s *Store) Delete(ctx context.Context, org, name string) (bool, error)

Delete removes an agent and its run history. Reports whether a row went.

func (*Store) DeleteTarget added in v1.801.23

func (s *Store) DeleteTarget(ctx context.Context, org, id string) (bool, error)

DeleteTarget removes an org's target. Sessions keep their recorded target id (a historical fact); a detached target simply stops appearing in the registry.

func (*Store) EventCountsByRoot added in v1.786.32

func (s *Store) EventCountsByRoot(ctx context.Context, org, root string) (map[string]int, error)

EventCountsByRoot returns per-session event counts for EVERY session in one org's tree (root_id == root) in a SINGLE grouped query — so materialising a tree of N nodes with real per-node event counts costs one round trip, not N, and never hits SQLite's bound-parameter limit (the join scopes by root_id, not an IN list of ids).

func (*Store) Get

func (s *Store) Get(ctx context.Context, org, name string) (Agent, error)

Get returns the agent for the exact (org,name) or errNotFound. It is the precise name primitive; path-addressed handlers use Resolve (id-or-name).

func (*Store) GetSession added in v1.786.32

func (s *Store) GetSession(ctx context.Context, org, id string) (Session, error)

GetSession returns the (org,id) session or errSessionNotFound. The org is part of the key so one tenant can never resolve another's session id.

func (*Store) GetTarget added in v1.801.23

func (s *Store) GetTarget(ctx context.Context, org, id string) (Target, error)

GetTarget returns the (org,id) target or errTargetNotFound. Org is part of the key so one tenant can never resolve another's target id.

func (*Store) GetTargetByHost added in v1.801.23

func (s *Store) GetTargetByHost(ctx context.Context, org, host string) (Target, error)

GetTargetByHost returns an org's target reporting the given host, or errTargetNotFound. It is how a re-link of the SAME machine finds its existing target (idempotent register) instead of creating a duplicate. Org-scoped: a host string can never resolve another tenant's target. Newest wins if a host was ever double-listed.

func (*Store) InsertRun

func (s *Store) InsertRun(ctx context.Context, r Run) error

InsertRun records one agent execution.

func (*Store) LastEvent added in v1.801.23

func (s *Store) LastEvent(ctx context.Context, org, sessionID string) (Event, bool, error)

LastEvent returns a session's most recent event (highest seq) — the one-line "last activity" a mission-control card shows in the list without fetching full detail. ok=false when the session has no events yet. Org-scoped like every read.

func (*Store) List

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

List returns every agent for org, most-recently-updated first.

func (*Store) ListEvents added in v1.786.32

func (s *Store) ListEvents(ctx context.Context, org, sessionID string, since int64, limit int) ([]Event, error)

ListEvents returns a session's events in Seq order (optionally only those with Seq > since, so a subscriber resumes exactly where it dropped), capped.

func (*Store) ListLongRunning added in v1.786.32

func (s *Store) ListLongRunning(ctx context.Context) ([]Agent, error)

ListLongRunning returns every agent across ALL orgs whose execution_mode is long-running and that carries a non-empty schedule — the scheduler's work set. It is the ONE cross-org query in this store; the scheduler is a trusted in-process subsystem (not a tenant request), and each returned agent carries its own Org so every downstream action (run, gate, meter) stays scoped to the agent's own tenant.

func (*Store) ListRuns

func (s *Store) ListRuns(ctx context.Context, org, agent string, limit int) ([]Run, error)

ListRuns returns the run history for (org,agent), newest first, capped.

func (*Store) ListSessions added in v1.786.32

func (s *Store) ListSessions(ctx context.Context, org string, f SessionFilter) ([]Session, error)

ListSessions returns an org's sessions per filter, newest first, capped.

func (*Store) ListTargets added in v1.801.23

func (s *Store) ListTargets(ctx context.Context, org string) ([]Target, error)

ListTargets returns an org's targets, newest first.

func (*Store) ListTree added in v1.786.32

func (s *Store) ListTree(ctx context.Context, org, root string, cap int) ([]Session, error)

ListTree returns EVERY session in one org's tree (root_id == root), oldest first so a caller can assemble parent→child in a single pass. Capped so a pathological tree can't produce an unbounded response.

func (*Store) Resolve added in v1.786.32

func (s *Store) Resolve(ctx context.Context, org, ref string) (Agent, error)

Resolve returns the agent identified by ref within org, matching either its public id (the `agent_...` handle create and list hand back) OR its org-unique name. This is the ONE lookup every path-addressed handler (get/update/delete/ run/runs) uses, so a just-created agent is immediately addressable by exactly the identifier create/list returned — no id-vs-name split. If a ref somehow equals one agent's id and another's name, the id match wins (the stable public handle is authoritative). Tenancy is the org filter, so a ref belonging to another tenant is errNotFound — fail-closed, never cross-org.

func (*Store) RunsSince added in v1.786.32

func (s *Store) RunsSince(ctx context.Context, org string, since int64, limit int) ([]Run, error)

RunsSince returns the org's runs across ALL agents with created_at >= since, newest first, capped. It powers the org-wide surfaces: the recent-activity feed (since=0 → the newest runs regardless of age) and the invocation histogram (since=windowStart → every run in the window, order-independent for bucketing). since<=0 means "no lower bound". Tenancy is the org column, so a caller never sees another org's runs. Every row is a real recorded execution.

func (*Store) SessionLoad added in v1.801.23

func (s *Store) SessionLoad(ctx context.Context, org, id, host string) (TargetLoad, error)

SessionLoad returns how many of an org's sessions are mapped to a target: those explicitly dispatched to it (target == id) OR reporting its host (host == host, when the target has a host). One exact query (no double count) per target — the list is small so the per-row cost matches the sessions list's own rollups.

func (*Store) StampServing added in v1.801.79

func (s *Store) StampServing(ctx context.Context, org, targetID string, now int64) error

StampServing records that a target's runner polled at now (its liveness heartbeat). Best-effort by the caller; a missing row is a no-op.

func (*Store) TargetDispatchable added in v1.801.79

func (s *Store) TargetDispatchable(ctx context.Context, org, targetID string) error

TargetDispatchable is the DRY liveness gate, used at dispatch (fail closed before enqueue) AND re-checked at claim. A run is dispatchable only to a target that (a) exists in this org, (b) is online, and (c) has a live runner — a claim poll within servingTTL. Any failure is an explicit error the dispatcher renders honestly; it NEVER falls back to running elsewhere.

func (*Store) Update

func (s *Store) Update(ctx context.Context, a Agent) error

Update overwrites the mutable fields of an existing agent.

func (*Store) UpdateSession added in v1.786.32

func (s *Store) UpdateSession(ctx context.Context, x Session) error

UpdateSession persists status/title/ended_at for an existing (org,id) session. Scoped by org so a cross-tenant id can never mutate another's session.

func (*Store) UpdateTarget added in v1.801.23

func (s *Store) UpdateTarget(ctx context.Context, t Target) error

UpdateTarget persists mutable fields for an existing (org,id) target. Scoped by org so a cross-tenant id can never mutate another's target.

func (*Store) UpsertClaimKeyHash added in v1.801.79

func (s *Store) UpsertClaimKeyHash(ctx context.Context, org, targetID, hash string, now int64) error

UpsertClaimKeyHash stores (or rotates) a target's claim-key hash. serving_at is reset to 0 on a fresh mint — the daemon proves liveness by its first poll.

type Target added in v1.801.23

type Target struct {
	ID        string
	Org       string
	Label     string
	Kind      string // laptop | cloud | gpu | cluster | machine
	Status    string // online | offline | draining
	Capacity  string // free-form ("8 vCPU / 32G", "1× GB10") — human summary
	Host      string // hostname sessions on this machine report (maps sessions -> target)
	Spec      Spec   // static capability
	Metrics   Metrics
	MetricsAt int64
	CreatedAt int64
	UpdatedAt int64
}

Target is a registered agent run-target. Owned by one org. Spec is its static capability (os/arch/cpus/memory/gpus) and Metrics its last live heartbeat (loadavg/memory/gpu-util); MetricsAt is the unix second that heartbeat was recorded (0 = never). See targetspec.go for the value plane.

func ResolveTarget added in v1.801.79

func ResolveTarget(ctx context.Context, org, ref string) (Target, error)

ResolveTarget resolves a human's target REFERENCE — a target id or its friendly label (the hostname the CLI registers) — to the org's target, org-scoped and fail-closed. It is the ONE way a trigger surface (the Slack `code: <repo> on <target>` grammar, a console picker) turns "on evo" into a target id without leaking another tenant's inventory: an id or label that resolves to no target in THIS org returns errTargetNotFound, never another org's machine.

Precedence: an exact id match wins (ids are unambiguous), else an exact, case-folded label match (newest first, so a re-registered machine's live row is preferred). A reference that matches neither is not found — the caller renders an honest error and NEVER falls back to a local run.

func TargetsForOrg added in v1.801.59

func TargetsForOrg(ctx context.Context, org string) ([]Target, error)

TargetsForOrg returns the org's registered run-targets from the in-process store, newest first. Fails closed when the subsystem is not mounted or the org is empty/oversized.

type TargetLoad added in v1.801.23

type TargetLoad struct {
	Sessions int // total sessions mapped to the target
	Running  int // of those, how many are currently running
}

TargetLoad is the live session load on a target.

func LoadOn added in v1.801.59

func LoadOn(ctx context.Context, org, id, host string) (TargetLoad, error)

LoadOn returns the live session load on one of the org's targets — the same (target id OR host) mapping the HTTP views use, so the board and /v1/agents/ targets can never disagree about what is running where.

type TaskController added in v1.786.32

type TaskController interface {
	// Signal forwards a cooperative control signal (pause/resume/message) to the
	// durable workflow backing a session. name is the signal name; payload is the
	// opaque signal argument (e.g. a steer message), nil when there is none.
	Signal(ctx context.Context, workflowID, runID, name string, payload []byte) error
	// Cancel gracefully cancels the durable workflow backing a session (a stop).
	Cancel(ctx context.Context, workflowID, runID, reason string) error
	// Enabled reports whether a real tasks backend is wired. When false the
	// control endpoints record the intent and skip the forward (honest degrade,
	// same pattern as deps.AI).
	Enabled() bool
}

TaskController is the seam to the hanzoai/tasks durable-execution engine — the ONE canonical engine for durable/retriable/scheduled agent work. This sessions surface is the REGISTRY + control + ZAP-stream VIEW layer; it deliberately owns NO scheduler, ticker, or lease. When a session is backed by a tasks workflow (Session.TaskWorkflowID set), a control command forwards through this seam to the engine's signal/cancel API instead of only being recorded.

The method set mirrors github.com/hanzoai/tasks/pkg/sdk/client.Client exactly, so the live adapter is a thin wrapper (Signal→Client.SignalWorkflow, Cancel→Client.CancelWorkflow) with no impedance mismatch:

SignalWorkflow(ctx, workflowID, runID, signalName string, arg any) error
CancelWorkflow(ctx, workflowID, runID string) error

TASKS PLUG-IN POINT. The live controller is wired in Mount from a dialed tasks client (client.Dial(TASKS_URL)); until the hanzoai/tasks native engine lands (today its workflow opcodes return 501 by design — "the shape is in place so callers depend on the API while the engine lands behind it"), the default is the disabled controller: control is still durably RECORDED as a session event for stream-consuming surfaces, and the forward is a clean no-op.

Jump to

Keyboard shortcuts

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