agents

package
v0.2.3 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2026 License: Apache-2.0 Imports: 22 Imported by: 0

Documentation

Overview

Package agents is the domain of agent-manager: an agent on the platform is a Flux HelmRelease of the agent chart (one release renders one kagent Agent), sharing a per-namespace OCIRepository that tracks the chart. The package composes those two objects exactly like the portal's create flow, validates the values against the chart's schema before anything is applied, and reads the agent back from the Agent CR, its owning HelmRelease and the workload kagent runs for it.

Index

Constants

View Source
const (
	DefaultChartOCIURL             = "oci://gsoci.azurecr.io/charts/giantswarm/agent"
	DefaultChartSemver             = "x.x.x"
	DefaultHelmReleaseInterval     = "10m"
	DefaultOCIRepositoryInterval   = "30m"
	DefaultHelmReleaseAPIVersion   = "helm.toolkit.fluxcd.io/v2"
	DefaultOCIRepositoryAPIVersion = "source.toolkit.fluxcd.io/v1"
)

Defaults of the composition, the values composeManifests.ts uses.

View Source
const (
	// DisplayNameAnnotation is the agent chart's contract for the friendly name.
	DisplayNameAnnotation = "ui.giantswarm.io/display-name"
	// HelmReleaseNameLabel / HelmReleaseNamespaceLabel are the Flux provenance
	// labels helm-controller stamps on every object a release renders.
	HelmReleaseNameLabel      = "helm.toolkit.fluxcd.io/name"
	HelmReleaseNamespaceLabel = "helm.toolkit.fluxcd.io/namespace"
	// KustomizationNameLabel marks a HelmRelease whose desired state lives in
	// git (applied by a Flux Kustomization): a live write would be undone on
	// the next reconciliation.
	KustomizationNameLabel = "kustomize.toolkit.fluxcd.io/name"
	// ManagedByLabel / ManagedByValue mark the HelmReleases and
	// OCIRepositories agent-manager created.
	ManagedByLabel = "app.kubernetes.io/managed-by"
	ManagedByValue = "agent-manager"
)

Labels and annotations the platform agrees on.

View Source
const (
	// ManagedHelmRelease: a HelmRelease owns the agent and can be written live.
	ManagedHelmRelease = "helmrelease"
	// ManagedGitOps: the owning HelmRelease is applied by a Flux Kustomization;
	// changes belong in git (the meta agent opens a PR instead).
	ManagedGitOps = "gitops"
	// ManagedNone: a bare Agent CR with no HelmRelease behind it.
	ManagedNone = "none"
)

How an agent is managed.

View Source
const (
	VerdictReady       = "ready"
	VerdictProgressing = "progressing"
	VerdictFailed      = "failed"
	VerdictUnknown     = "unknown"
)

Verdicts of a status check.

Variables

View Source
var (
	// ErrNotFound: the agent, HelmRelease or ModelConfig does not exist.
	ErrNotFound = errors.New("not found")
	// ErrInvalid: the request is malformed or fails the chart's values schema.
	ErrInvalid = errors.New("invalid request")
	// ErrConflict: the object exists, is owned by GitOps, is suspended, or is
	// a bare Agent CR — a write would be refused or undone; force overrides
	// where documented.
	ErrConflict = errors.New("conflict")
	// ErrForbidden: the Kubernetes API refused the write for the identity
	// agent-manager runs with.
	ErrForbidden = errors.New("forbidden")
	// ErrUnsupported: the operation is not available on this installation.
	ErrUnsupported = errors.New("unsupported")
	// ErrUnauthenticated: the request reached the service without the caller
	// token it needs to act (the server runs as the caller only). 401.
	ErrUnauthenticated = errors.New("unauthenticated")
)

Sentinel errors the API layers map to HTTP statuses and MCP error codes.

Functions

func BuildHelmRelease

func BuildHelmRelease(name, namespace string, values map[string]any, cfg ComposeConfig) *unstructured.Unstructured

BuildHelmRelease composes the HelmRelease of an agent.

func BuildOCIRepository

func BuildOCIRepository(namespace string, cfg ComposeConfig) *unstructured.Unstructured

BuildOCIRepository composes the shared chart source of a namespace.

func BuildValues

func BuildValues(spec Spec) map[string]any

BuildValues composes the chart values from a spec. Only what the caller set is emitted so the chart's defaults apply to everything else — the same rule as the portal (an empty prompt means "the chart's default prompt").

func SkillName

func SkillName(g SkillGitRef) string

SkillName is the directory a git skill mounts under: the explicit name, else the last path segment, else the repository name.

func ToYAML

func ToYAML(obj *unstructured.Unstructured) string

ToYAML renders an object as YAML (what the applied manifest looks like).

func ValidateName

func ValidateName(name string) error

ValidateName checks the technical name: a DNS-1123 label of at most 63 characters, as the Agent CRD, Helm and the chart's schema require.

func ValidateValues

func ValidateValues(ctx context.Context, src SchemaSource, values map[string]any) (chart.Schema, []string)

ValidateValues checks values against the chart's schema and returns every violation as a readable line (path: message). A schema that does not compile is reported as one error rather than letting invalid values through.

Types

type Agent

type Agent struct {
	Name      string `json:"name"`
	Namespace string `json:"namespace"`
	// Exists is false while the HelmRelease has not rendered the Agent CR yet
	// (or failed to).
	Exists        bool     `json:"exists"`
	DisplayName   string   `json:"displayName,omitempty"`
	Description   string   `json:"description,omitempty"`
	ModelConfig   string   `json:"modelConfig,omitempty"`
	Runtime       string   `json:"runtime,omitempty"`
	IconURL       string   `json:"iconUrl,omitempty"`
	SystemMessage string   `json:"systemMessage,omitempty"`
	Skills        *Skills  `json:"skills,omitempty"`
	ToolNames     []string `json:"toolNames,omitempty"`
	// Ready / Accepted mirror the Agent CR's conditions; nil while unreported
	// or when the CR is absent.
	Ready      *bool       `json:"ready"`
	Accepted   *bool       `json:"accepted"`
	Conditions []Condition `json:"conditions,omitempty"`
	// Managed is helmrelease, gitops or none.
	Managed     string          `json:"managed"`
	HelmRelease *HelmReleaseRef `json:"helmRelease,omitempty"`
	// Values are the HelmRelease's inline values (the chart contract), when a
	// HelmRelease owns the agent.
	Values map[string]any `json:"values,omitempty"`
}

Agent is the read model of one agent.

type AgentStatus

type AgentStatus struct {
	Exists     bool        `json:"exists"`
	Ready      *bool       `json:"ready"`
	Accepted   *bool       `json:"accepted"`
	Conditions []Condition `json:"conditions,omitempty"`
}

AgentStatus is the Agent CR's status.

type ChartRef

type ChartRef struct {
	Kind      string `json:"kind"`
	Name      string `json:"name"`
	Namespace string `json:"namespace,omitempty"`
}

ChartRef is a HelmRelease's spec.chartRef.

type ChartSource

type ChartSource interface {
	SchemaSource
	Info(ctx context.Context) chart.Info
	Name() string
	OCIURL() string
	SemverRange() string
}

ChartSource is what the service needs to know about the agent chart.

type ComposeConfig

type ComposeConfig struct {
	// ChartOCIURL is the agent chart, e.g. oci://gsoci.azurecr.io/charts/giantswarm/agent.
	ChartOCIURL string
	// ChartName is the OCIRepository's name (the chart name).
	ChartName string
	// ChartSemver is the OCIRepository ref.semver range (x.x.x).
	ChartSemver string
	// HelmReleaseInterval / OCIRepositoryInterval are the Flux intervals.
	HelmReleaseInterval   string
	OCIRepositoryInterval string
	// ServiceAccountName is HelmRelease.spec.serviceAccountName, required by a
	// Flux multi-tenancy admission policy in tenant namespaces; empty omits it.
	ServiceAccountName string
	// HelmReleaseAPIVersion / OCIRepositoryAPIVersion are the served Flux API
	// versions (helm.toolkit.fluxcd.io/v2, source.toolkit.fluxcd.io/v1).
	HelmReleaseAPIVersion   string
	OCIRepositoryAPIVersion string
}

ComposeConfig is the platform side of the composition.

type Condition

type Condition struct {
	Type               string `json:"type"`
	Status             string `json:"status"`
	Reason             string `json:"reason,omitempty"`
	Message            string `json:"message,omitempty"`
	LastTransitionTime string `json:"lastTransitionTime,omitempty"`
}

Condition is a Kubernetes-style status condition, flattened.

type Config

type Config struct {
	// DefaultNamespace receives agents when a request names none.
	DefaultNamespace string
	// ManagedNamespaces are the namespaces the service may read and write
	// (RBAC exists there); DefaultNamespace is always included.
	ManagedNamespaces []string
	// Compose is the platform side of the manifests.
	Compose ComposeConfig
	// KagentAPIVersion is the served kagent.dev version (v1alpha2).
	KagentAPIVersion string
	// Version is the service version reported by GET /info.
	Version string
}

Config configures the service.

type ContainerStatus

type ContainerStatus struct {
	Name    string `json:"name"`
	State   string `json:"state"`
	Reason  string `json:"reason,omitempty"`
	Message string `json:"message,omitempty"`
	// Init marks an init container (skills-init).
	Init bool `json:"init,omitempty"`
}

ContainerStatus is a container's state when it is not running normally.

type CreateResult

type CreateResult struct {
	Agent     Agent     `json:"agent"`
	Manifests Manifests `json:"manifests"`
	// Created says which objects were new; the OCIRepository is shared per
	// namespace and reused when it exists.
	Created struct {
		OCIRepository bool `json:"ociRepository"`
		HelmRelease   bool `json:"helmRelease"`
	} `json:"created"`
	Status *Status `json:"status,omitempty"`
	// RequestedBy is the authenticated caller the write ran as (email, else
	// subject); empty when the server runs without OAuth.
	RequestedBy string `json:"requestedBy,omitempty"`
}

CreateResult reports what a create applied.

type DeleteResult

type DeleteResult struct {
	Name                 string `json:"name"`
	Namespace            string `json:"namespace"`
	HelmReleaseDeleted   bool   `json:"helmReleaseDeleted"`
	AgentDeleted         bool   `json:"agentDeleted"`
	OCIRepositoryDeleted bool   `json:"ociRepositoryDeleted"`
	// OCIRepositoryKept explains why the chart source stays (other agents
	// reference it, or it could not be checked).
	OCIRepositoryKept string `json:"ociRepositoryKept,omitempty"`
	// RequestedBy is the authenticated caller the delete ran as.
	RequestedBy string `json:"requestedBy,omitempty"`
}

DeleteResult reports what a delete removed.

type DeploymentStatus

type DeploymentStatus struct {
	Exists            bool        `json:"exists"`
	Replicas          int32       `json:"replicas"`
	ReadyReplicas     int32       `json:"readyReplicas"`
	AvailableReplicas int32       `json:"availableReplicas"`
	Conditions        []Condition `json:"conditions,omitempty"`
}

DeploymentStatus is the kagent-managed Deployment of the agent.

type Event

type Event struct {
	Type    string `json:"type"`
	Reason  string `json:"reason"`
	Message string `json:"message"`
	Object  string `json:"object"`
	Count   int32  `json:"count,omitempty"`
	Last    string `json:"lastTimestamp,omitempty"`
}

Event is a recent Warning event on the agent's objects.

type HelmReleaseHistory

type HelmReleaseHistory struct {
	Version      int64  `json:"version"`
	ChartVersion string `json:"chartVersion,omitempty"`
	Status       string `json:"status,omitempty"`
	LastDeployed string `json:"lastDeployed,omitempty"`
}

HelmReleaseHistory is one Helm release revision from status.history.

type HelmReleaseRef

type HelmReleaseRef struct {
	Name      string `json:"name"`
	Namespace string `json:"namespace"`
	// Ready mirrors the Ready condition; nil while unreported.
	Ready   *bool  `json:"ready"`
	Reason  string `json:"reason,omitempty"`
	Message string `json:"message,omitempty"`
	// ChartVersion is the deployed chart version (last history entry), else
	// the last attempted revision.
	ChartVersion          string `json:"chartVersion,omitempty"`
	LastAttemptedRevision string `json:"lastAttemptedRevision,omitempty"`
	Suspended             bool   `json:"suspended"`
	GitOpsOwned           bool   `json:"gitOpsOwned"`
	// Deleting is true while helm-controller uninstalls the release (the
	// HelmRelease carries a deletionTimestamp); the Agent disappears with it.
	Deleting bool      `json:"deleting"`
	ChartRef *ChartRef `json:"chartRef,omitempty"`
}

HelmReleaseRef is what an agent view says about its owning release.

type HelmReleaseStatus

type HelmReleaseStatus struct {
	Exists                bool                 `json:"exists"`
	Ready                 *bool                `json:"ready"`
	Suspended             bool                 `json:"suspended"`
	GitOpsOwned           bool                 `json:"gitOpsOwned"`
	Deleting              bool                 `json:"deleting"`
	Conditions            []Condition          `json:"conditions,omitempty"`
	History               []HelmReleaseHistory `json:"history,omitempty"`
	LastAttemptedRevision string               `json:"lastAttemptedRevision,omitempty"`
}

HelmReleaseStatus is the release's conditions and recent history.

type InfoResponse

type InfoResponse struct {
	Version string     `json:"version"`
	Chart   chart.Info `json:"chart"`
	// Namespaces the service manages agents in.
	Namespaces struct {
		Default string   `json:"default"`
		Managed []string `json:"managed"`
	} `json:"namespaces"`
	// Capabilities are explicit flags; a false flag means the matching
	// operation answers 501 unsupported.
	Capabilities map[string]bool `json:"capabilities"`
	// Identity says how calls reach the API server: `caller` (every call
	// presents the signed-in user's IdP token; the user's RBAC governs) or
	// `serviceAccount` (the service's own identity behind a trusted proxy).
	Identity string `json:"identity"`
	// APIVersions are the served CRD versions the service composes and reads.
	APIVersions struct {
		Agent         string `json:"agent"`
		ModelConfig   string `json:"modelConfig"`
		HelmRelease   string `json:"helmRelease"`
		OCIRepository string `json:"ociRepository"`
	} `json:"apiVersions"`
	// Flux settings the composed HelmReleases carry.
	Flux struct {
		HelmReleaseInterval   string `json:"helmReleaseInterval"`
		OCIRepositoryInterval string `json:"ociRepositoryInterval"`
		ServiceAccountName    string `json:"serviceAccountName,omitempty"`
	} `json:"flux"`
	// SkillsRepositories are the configured skill repositories.
	SkillsRepositories []string `json:"skillsRepositories"`
}

InfoResponse is GET /info: what this installation can do, so the portal and agents feature-detect instead of guessing.

type Manifests

type Manifests struct {
	OCIRepository string         `json:"ociRepository"`
	HelmRelease   string         `json:"helmRelease"`
	Values        map[string]any `json:"values"`
}

Manifests are the objects a create/update applies, as YAML, plus the values.

func ComposeManifests

func ComposeManifests(name, namespace string, values map[string]any, cfg ComposeConfig) Manifests

ComposeManifests renders the pair for a namespace and values.

type ModelConfig

type ModelConfig struct {
	Name      string `json:"name"`
	Namespace string `json:"namespace"`
	Provider  string `json:"provider,omitempty"`
	Model     string `json:"model,omitempty"`
	// Accepted mirrors the kagent Accepted condition; nil while unreported.
	Accepted  *bool  `json:"accepted"`
	Message   string `json:"message,omitempty"`
	ManagedBy string `json:"managedBy,omitempty"`
}

ModelConfig is a kagent ModelConfig an agent can reference.

type PodStatus

type PodStatus struct {
	Name  string `json:"name"`
	Phase string `json:"phase"`
	Ready bool   `json:"ready"`
	// Containers lists non-running containers with their waiting/terminated
	// reason (CrashLoopBackOff, ImagePullBackOff, ...).
	Containers []ContainerStatus `json:"containers,omitempty"`
	Restarts   int32             `json:"restarts"`
}

PodStatus is one agent pod with what its containers are waiting on.

type SchemaSource

type SchemaSource interface {
	Schema(ctx context.Context) chart.Schema
}

SchemaSource provides the agent chart's values.schema.json.

type Service

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

Service is the agent lifecycle.

func New

New builds the service. skills may be nil (list_skills then reports unsupported).

func (*Service) Create

func (s *Service) Create(ctx context.Context, spec Spec) (*CreateResult, error)

Create composes and applies the OCIRepository (when missing) and the HelmRelease of a new agent after validating the values against the chart schema. Nothing is written when validation fails.

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, ns, name string, force bool) (*DeleteResult, error)

Delete removes the agent's HelmRelease (helm-controller uninstalls the Agent) and the shared OCIRepository when no other release references it. A bare Agent CR is only deleted with force.

func (*Service) Get

func (s *Service) Get(ctx context.Context, ns, name string) (*Agent, error)

Get returns one agent by name.

func (*Service) Info

func (s *Service) Info(ctx context.Context) InfoResponse

Info reports the installation's capabilities.

func (*Service) List

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

List returns the agents of a namespace: every Agent CR (with its owning HelmRelease when Flux labels name one) plus every HelmRelease of the agent chart that has not rendered an Agent yet.

func (*Service) ListModelConfigs

func (s *Service) ListModelConfigs(ctx context.Context, ns string) ([]ModelConfig, error)

ListModelConfigs lists the kagent ModelConfigs of a namespace.

func (*Service) ListSkills

func (s *Service) ListSkills(ctx context.Context, repository, ref string, refresh bool) (*skills.Result, error)

ListSkills discovers skills in the configured (or the given) repository.

func (*Service) Namespace

func (s *Service) Namespace(ns string) (string, error)

Namespace resolves an optional namespace argument against the managed set.

func (*Service) Status

func (s *Service) Status(ctx context.Context, ns, name string) (*Status, error)

Status gathers the Agent CR, the owning HelmRelease (conditions, history), the Deployment kagent runs and its pods (waiting reasons — a crash-looping pod is phase Running, so containerStatuses are what tell) and the recent Warning events, and folds them into one verdict.

func (*Service) Update

func (s *Service) Update(ctx context.Context, upd Update) (*UpdateResult, error)

Update merges the change into the HelmRelease values, validates the result against the chart schema and writes it. The Agent CR itself is never touched: helm-controller renders the change.

func (*Service) ValidateCreate

func (s *Service) ValidateCreate(ctx context.Context, spec Spec) (*ValidateResult, error)

ValidateCreate is create_agent without the write.

func (*Service) ValidateUpdate

func (s *Service) ValidateUpdate(ctx context.Context, upd Update) (*ValidateResult, error)

ValidateUpdate is update_agent without the write.

type SkillGitRef

type SkillGitRef struct {
	// URL of the git repository.
	URL string `json:"url"`
	// Path is the subdirectory holding SKILL.md; empty for the repository root.
	Path string `json:"path,omitempty"`
	// Ref is a branch, tag or commit; empty means the default branch.
	Ref string `json:"ref,omitempty"`
	// Name is the directory the skill is mounted under (/skills/<name>);
	// defaults to the last path segment, else the repository name.
	Name string `json:"name,omitempty"`
}

SkillGitRef is one kagent spec.skills.gitRefs entry (chart values skills.gitRefs[]): a git repository plus the subdirectory that is the skill.

type Skills

type Skills struct {
	// Refs are OCI skill image references.
	Refs []string `json:"refs,omitempty"`
	// GitRefs are git repository references.
	GitRefs []SkillGitRef `json:"gitRefs,omitempty"`
	// GitAuthSecretName names a Secret in the agent's namespace for private
	// gitRefs (key token, or a kubernetes.io/ssh-auth secret).
	GitAuthSecretName string `json:"gitAuthSecretName,omitempty"`
}

Skills mirrors the agent chart's skills block.

func (*Skills) IsEmpty

func (s *Skills) IsEmpty() bool

IsEmpty reports whether no skill is referenced.

type Spec

type Spec struct {
	// Namespace the agent lives in; empty selects the default managed namespace.
	Namespace string `json:"namespace,omitempty"`
	// Name is the DNS-1123 technical name: the HelmRelease name and the Agent
	// name. The caller confirms it; agent-manager never derives it.
	Name string `json:"name"`
	// DisplayName is the friendly Unicode name (max 63 chars).
	DisplayName string `json:"displayName,omitempty"`
	// Description goes to Agent.spec.description.
	Description string `json:"description,omitempty"`
	// SystemMessage is the system prompt; empty keeps the chart default.
	SystemMessage string `json:"systemMessage,omitempty"`
	// ModelConfig names an existing kagent ModelConfig in the namespace.
	ModelConfig string `json:"modelConfig"`
	// IconURL is the avatar URL (chart agent.iconUrl).
	IconURL string `json:"iconUrl,omitempty"`
	// Runtime is go or python; empty keeps the chart default (go).
	Runtime string `json:"runtime,omitempty"`
	// Skills the agent mounts.
	Skills *Skills `json:"skills,omitempty"`
	// ToolNames narrows the muster tools; empty means every tool the gateway
	// exposes (chart default).
	ToolNames []string `json:"toolNames,omitempty"`
	// Labels / Annotations are merged onto the Agent by the chart.
	Labels      map[string]string `json:"labels,omitempty"`
	Annotations map[string]string `json:"annotations,omitempty"`
}

Spec is what a caller provides to create an agent. Everything but Name and ModelConfig is optional; omitted fields keep the chart's defaults.

type Status

type Status struct {
	Name      string `json:"name"`
	Namespace string `json:"namespace"`
	// Verdict is ready, progressing, failed or unknown.
	Verdict string `json:"verdict"`
	// Summary is one sentence a human or an agent can act on.
	Summary     string             `json:"summary"`
	Agent       *AgentStatus       `json:"agent,omitempty"`
	HelmRelease *HelmReleaseStatus `json:"helmRelease,omitempty"`
	Deployment  *DeploymentStatus  `json:"deployment,omitempty"`
	Pods        []PodStatus        `json:"pods,omitempty"`
	Events      []Event            `json:"events,omitempty"`
}

Status is the compact verdict of get_agent_status.

type Update

type Update struct {
	Namespace     string             `json:"namespace,omitempty"`
	Name          string             `json:"name"`
	DisplayName   *string            `json:"displayName,omitempty"`
	Description   *string            `json:"description,omitempty"`
	SystemMessage *string            `json:"systemMessage,omitempty"`
	ModelConfig   *string            `json:"modelConfig,omitempty"`
	IconURL       *string            `json:"iconUrl,omitempty"`
	Runtime       *string            `json:"runtime,omitempty"`
	Skills        *Skills            `json:"skills,omitempty"`
	ToolNames     *[]string          `json:"toolNames,omitempty"`
	Labels        *map[string]string `json:"labels,omitempty"`
	Annotations   *map[string]string `json:"annotations,omitempty"`
	// Force writes to a GitOps-owned or suspended HelmRelease anyway.
	Force bool `json:"force,omitempty"`
}

Update is a partial change to an existing agent: nil pointers leave the current value; a pointer to an empty value clears it (falls back to the chart default). Skills and ToolNames replace the whole block.

type UpdateResult

type UpdateResult struct {
	Agent     Agent          `json:"agent"`
	Before    map[string]any `json:"before"`
	After     map[string]any `json:"after"`
	Changed   []string       `json:"changed"`
	Manifests Manifests      `json:"manifests"`
	// RequestedBy is the authenticated caller the write ran as.
	RequestedBy string `json:"requestedBy,omitempty"`
}

UpdateResult reports before/after values of an update.

type ValidateResult

type ValidateResult struct {
	Valid bool `json:"valid"`
	// Mode is create or update.
	Mode string `json:"mode"`
	// Errors lists every schema violation and precondition failure.
	Errors []string `json:"errors,omitempty"`
	// SchemaVersion / SchemaSource say which chart schema judged the values.
	SchemaVersion string    `json:"schemaVersion"`
	SchemaSource  string    `json:"schemaSource"`
	Manifests     Manifests `json:"manifests"`
}

ValidateResult is a dry run: nothing was written.

Jump to

Keyboard shortcuts

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