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
- Variables
- func BuildHelmRelease(name, namespace string, values map[string]any, cfg ComposeConfig) *unstructured.Unstructured
- func BuildOCIRepository(namespace string, cfg ComposeConfig) *unstructured.Unstructured
- func BuildValues(spec Spec) map[string]any
- func SkillName(g SkillGitRef) string
- func ToYAML(obj *unstructured.Unstructured) string
- func ValidateName(name string) error
- func ValidateValues(ctx context.Context, src SchemaSource, values map[string]any) (chart.Schema, []string)
- type Agent
- type AgentStatus
- type ChartRef
- type ChartSource
- type ComposeConfig
- type Condition
- type Config
- type ContainerStatus
- type CreateResult
- type DeleteResult
- type DeploymentStatus
- type Event
- type HelmReleaseHistory
- type HelmReleaseRef
- type HelmReleaseStatus
- type InfoResponse
- type Manifests
- type ModelConfig
- type PodStatus
- type SchemaSource
- type Service
- func (s *Service) Create(ctx context.Context, spec Spec) (*CreateResult, error)
- func (s *Service) Delete(ctx context.Context, ns, name string, force bool) (*DeleteResult, error)
- func (s *Service) Get(ctx context.Context, ns, name string) (*Agent, error)
- func (s *Service) Info(ctx context.Context) InfoResponse
- func (s *Service) List(ctx context.Context, ns string) ([]Agent, error)
- func (s *Service) ListModelConfigs(ctx context.Context, ns string) ([]ModelConfig, error)
- func (s *Service) ListSkills(ctx context.Context, repository, ref string, refresh bool) (*skills.Result, error)
- func (s *Service) Namespace(ns string) (string, error)
- func (s *Service) Status(ctx context.Context, ns, name string) (*Status, error)
- func (s *Service) Update(ctx context.Context, upd Update) (*UpdateResult, error)
- func (s *Service) ValidateCreate(ctx context.Context, spec Spec) (*ValidateResult, error)
- func (s *Service) ValidateUpdate(ctx context.Context, upd Update) (*ValidateResult, error)
- type SkillGitRef
- type Skills
- type Spec
- type Status
- type Update
- type UpdateResult
- type ValidateResult
Constants ¶
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.
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.
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.
const ( VerdictReady = "ready" VerdictProgressing = "progressing" VerdictFailed = "failed" VerdictUnknown = "unknown" )
Verdicts of a status check.
Variables ¶
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") )
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 ¶
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 ¶
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"`
}
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"`
}
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 writes reach the API server: serviceAccount (the
// service's own identity behind the gateway's JWT policy).
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 ¶
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 ¶
func New(k kube.Provider, c ChartSource, s *skills.Discoverer, cfg Config, log *slog.Logger) *Service
New builds the service. skills may be nil (list_skills then reports unsupported).
func (*Service) Create ¶
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 ¶
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) Info ¶
func (s *Service) Info(ctx context.Context) InfoResponse
Info reports the installation's capabilities.
func (*Service) List ¶
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 ¶
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 ¶
Namespace resolves an optional namespace argument against the managed set.
func (*Service) Status ¶
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 ¶
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 ¶
ValidateCreate is create_agent without the write.
func (*Service) ValidateUpdate ¶
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.
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"`
}
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.