AI Agents

  • Fixed

    • The managers take their login from muster’s OAuth server block (giantswarm/agent-platform#484): model-manager — on by default — failed on every installation that set global.identity.issuerUrl alone (oauth.dex.clientSecret or oauth.existingSecret is required when oauth.enabled, the child release’s error), and a customer installation, whose muster logs in with its own Dex client, cannot take a fleet-wide global.identity.clientId. The meta chart now fills what a manager’s oauth block and global.identity leave unset from muster.muster.oauth.server (agent-platform.identity.apply, on the shaped values, so the connectivity release sees the same blocks): for model-manager, agent-manager, vm-manager and cluster-manager oauth.dex.issuerURL (dex.issuerUrl), oauth.dex.clientID with oauth.trustedAudiences: [<client>] (dex.clientId, the charts’ own default from global.identity.clientId) and oauth.existingSecret (existingSecret, key dex-client-secret), for the dex provider while muster’s OAuth server is on; for the two routed managers oauth.baseURL https://<route hostname><route.pathPrefix> under an agentgateway-* ingress.mode (modelManager.route.hostname / agentManager.route.hostname, else agentgateway.<global.domain>). A manager’s own value wins, and so does global.identity (nothing is filled then: the charts read it themselves). The connectivity chart’s model-manager guard gains its absence checks back once the installation names its login (muster’s OAuth server on with a Dex issuer): a missing issuer, client, secret or base URL fails the connectivity render naming the value to set; a render that names no login is untouched. make verify-managers asserts the four derivations, both winners, the one-login guard and the absence guard through the meta and connectivity renders. An installation that sets global.identity and the base URL explicitly renders byte-identically.
  • Added

    • The model cache claim carries its tier: the hook that applies modelServing.cache.pvc stamps agent-platform.giantswarm.io/volume-type, -iops and -throughput (MiB/s) on it (giantswarm/agent-platform#605). The claim outlives its StorageClass by design — the chart’s class is Helm-owned and digest-named, so an uninstall or a parameter change removes it while the claim stays — and the class was the only place the volume’s tier could be read from, so cluster-manager answered “no price” for a claim that costs money. The annotations carry the EBS CSI class parameters type, iops and throughput: the chart’s own as rendered when the claim is on the class the chart renders, else what the claim’s class carries when the hook runs. They are written once, at create or on the first run that finds a claim without any of them while its class exists, and left alone afterwards; kubectl annotate writes them, not the claim’s apply, so no later apply removes them. A claim whose class is gone or that names none is not stamped, and the hook’s log says why. cluster-manager reads the tier from the annotations where the class is gone (giantswarm/cluster-manager#99). make verify-serving-slice asserts the stamped claim. README “The claim’s tier”.

    Fixed

    • The cache claim hook can read StorageClasses: get on storageclasses for <release>-hooks while the claim is the chart’s (giantswarm/agent-platform#605). The hook asked whether a Pending claim’s class still exists with an identity that could not read any class, so the check always answered “gone” and a Pending claim on a class the cluster has failed the hook. The same get reads the class parameters the claim’s tier is stamped from.
  • Fixed

    • The capz snapshot-store identity also holds Storage Blob Delegator on the storage account (giantswarm/giantswarm#37705). Substrate 1.1.0’s golden tag copies the golden snapshot’s objects server-side, and s3proxy signs the copy source with a user delegation SAS; the key is an account-level action the container-scoped Data Contributor cannot grant, so on glean every copy failed with AuthorizationPermissionMismatch and no AgentTemplate reached Ready.
  • Fixed

    • The egress gateway reaches the Substrate credential provider (substrate-atenet-egress → k8s-credential-provider 50051), and the provider has its own policy (ingress from the gateway and the scrape port, egress to the apiserver) (giantswarm/giantswarm#37705). On the Substrate line from 1.1.0 the gateway asks the provider for every injected credential; without the hop each ask ended in UpstreamCallTimeout, the golden boot’s git fetch of a private skill got 403 and the AgentTemplate never left ActorTemplateRetrying. agentlab renders no network policies, so the gate could not see it.
  • Added

    • The LLM listener routes by model: every llmRouting.models entry is an AgentgatewayModel attached directly to the data plane’s LLM listener, and served models join it through the LLMEndpoint document (giantswarm/agent-platform#603). The request’s model picks the model; the default list is anthropic (provider Anthropic, baseURL: https://api.anthropic.com/v1 — agentgateway 2.1 builds the upstream path from the baseURL’s path, and a managed provider without one sends Anthropic /messages —, match: claude-*), credential-free as the AgentgatewayBackend it replaces. The models attach to the Gateway’s llm listener by sectionName, with no HTTPRoute and no path prefix in front: agentgateway 2.1.2 strips the matched PathPrefix of a rule whose backend is the model router, so a route at /v1 handed it /messages, which it proxied as Passthrough with no agentgateway_gen_ai_* token or cost metric, and the Gateway-scoped route-type map overrode its classification for every other path; listener-attached models match the serving endpoints (/v1/messages, /v1/chat/completions, …), which outrank the MCP catch-all. The in-cluster HTTPRoute, the route-type map policy and the llmRouting.pathPrefixes and llmRouting.routes values are gone; ModelConfig base URLs stay the listener’s origin with no path. With LLM routing and a serving model-manager — this release’s serving slice, or a GPU node pool’s, which comes as a second release of the chart with model-manager off — the chart renders the LLMEndpoint document (ConfigMap <name>-llm-endpoint, labelled agent-platform.giantswarm.io/llm-endpoint: "true": parentRefs exactly the provider models’, endpoint the listener’s in-cluster URL, externalEndpoint with the external endpoint), model-manager’s ServiceAccount gets a Role on the release namespace’s agentgatewaymodels and nothing else, and the data plane’s egress reaches the workload pods where model-manager serves (both flavours), so model-manager attaches one AgentgatewayModel per served model under its preset’s name (giantswarm/model-manager#145); the serving slice’s discovery ConfigMap no longer carries spec.llmEndpoint, which a node pool’s topology never rendered. llmRouting.external (off by default) puts the endpoint on https://llm.<global.domain> behind the installation’s API keys (apiKeyAuthentication Strict over one Secret or ConfigMap source) on a route at PathPrefix: / — a root model route, whose hostname outranks the catch-all: on the data plane’s HTTPS listener with the chart’s edge, else on a data-plane listener of its own, llmRouting.external.listener (llm-external, 8082), to which the public Gateway forwards the hostname and which the data-plane network policies admit from the cluster, since the controller refuses a root model route beside directly attached models; every model attaches to it, the LLMEndpoint document names it, and the data plane’s metrics carry each key’s metadata.name as api_key. A key reaches every model until agentgateway enforces allowedModels on the Kubernetes contract (the README says so). Breaking for an installation that set llmRouting.backend, llmRouting.pathPrefixes or llmRouting.routes: the schema refuses them; see UPGRADE.md. verify-llm-routing covers the listener-attached models and their guards (a duplicate name, a wildcard the CRD refuses, an empty list), the absence of the in-cluster route and the routes map, the external route and its listener in both edge shapes, the LLMEndpoint document’s content, the Role and the egress with this release’s slice and a node pool’s, and nothing of it without LLM routing or a serving model-manager.
  • Added

    • The Substrate bootstrap mints a fifth pool, egress-mitm-ca-pool (ECDSA P-256) in ate-system (giantswarm/giantswarm#37705). The Substrate line from 1.1.0 (kagent-dev/substrate v0.2.0-beta4) terminates and re-originates every TLS connection an actor opens and injects the agents’ credentials into the request at the egress gateway; the egress Deployment mounts this pool and does not start without it. The actors trust its roots through the egress-mitm.ate.dev trust bundle kagent projects. A pool that exists is kept, like the other four.
    • substrate.credentialProvider.namespacePolicies, the namespaces the Substrate credential provider may read Secrets from, one entry per namespace that hosts AgentTemplates and one for ate-golden (default: the kagent namespace for both). The egress gateway of the Substrate line from 1.1.0 injects an agent’s credentials from Secrets next to its AgentTemplate; without the grant every model call of the namespace fails. The golden actor of every template boots in Substrate’s atespace ate-golden and fetches the template’s private git skills with the template’s credential, so ate-golden is allowed the same namespaces; without it the golden boot of a template with a private skill fails with git’s 403.
    • A Kyverno PolicyException for the Substrate credential provider (substrate-credential-provider, check-seccomp-strict) (giantswarm/giantswarm#37705). The k8s-credential-provider Deployment of Substrate 1.1.0 runs non-root with every capability dropped but declares no seccompProfile; without the exception the restricted policy denies it on the fleet. make verify-kyverno holds the rule list to the rendered pod spec.
    • kagent.harness.compaction, the context compaction of every agent the platform Harness admits (tokenThreshold: 24000, eventRetentionSize: 4, the values the Generic agent chart rendered per AgentTemplate). kagent-dev/kagent#2790 put compaction on Harness.spec.kagent.compaction; the kagent line from 1.1.0 renders the block from this value and the AgentTemplate has no such field any more.

    Changed

    • components.kagent*.versionRange and components.substrate*.versionRange are >=1.1.0 <1.2.0, agent-manager.agentChart.semver is >=1.5.0 <2.0.0 (was >=1.0.0 <1.5.0); the example BOM pins 1.1.0 (giantswarm/giantswarm#37705). The kagent line’s 1.1.0 is upstream main@1069fd2 (2026-09-24) on the Substrate line’s 1.1.0, kagent-dev/substrate v0.2.0-beta5 plus the carried patches, the contract the values of this release are written for (the egress MITM pool, the registry split, the credential provider’s policies, the Harness compaction); the 1.0 lines stay on their release-1.0 branches for the installations that do not move yet. Generic agent chart 1.5.0 renders no spec.context.compaction, which this kagent refuses, so the agent chart floor moves with the lines. Proven on agentlab on the lines’ dev builds: platform-test, a2a-test, skills-test public and private, agents-test.
    • substrate.image.registry is the registry host only, gsoci.azurecr.io, and the new substrate.image.repository the path under it, giantswarm/substrate (the Substrate chart’s registry/repository split, kagent-dev/substrate df5265f9, in the line from 1.1.0; the chart refuses a registry that carries a path). The derived worker image follows both, <registry>/<repository>/ateom-gvisor:<floor>. A mirror moves the registry alone.
  • Fixed

    • model-manager reads a served model’s route list on a cluster whose serving slice a GPU node pool brought (giantswarm/agent-platform#602). create_node_pool installs the slice as a second release of the chart, with model-manager off, and the platform release keeps modelServing off; model-manager’s egress rule into the serving namespace was conditioned on that release’s own modelServing, so it never rendered and every model served on the pool reported no interfaces. The rule now renders whenever model-manager serves — the slice on, a static kserve backend or cluster-manager on — into this release’s serving namespace, else model-manager’s kserve.namespace. The slice’s side is giantswarm/cluster-manager#103.
  • Added

    • Every shipped serving preset is checked against its model family’s parsers: files/model-serving/model-families.yaml and a verify-serving-slice check (giantswarm/agent-platform#313). The tool-call parser, the reasoning parser and the chat template are facts of a model’s architecture; the table names them per family (gpt-oss, Gemma 4, Mistral, Nemotron 3, Qwen3.5/3.6, Qwen3.8), matched on spec.model.id, each row citing its vLLM recipe, every parser one the runtime’s vLLM 0.23 registers. A preset tagged tools without --enable-auto-tool-choice and a family tool-call parser, one tagged reasoning without the family’s reasoning parser, a parser the family does not list and a preset of a family the table lacks fail naming preset, family and parser. The Qwen3.8 row allows qwen3_coder and qwen3_xml and says why: both parse the one tool-call format the family’s template writes, and vLLM’s recipes name both.

    Fixed

    • devstral-small-2 and nemotron-3-super-nvfp4 serve tool calls (giantswarm/agent-platform#313): both were tagged tools without a tool-call parser, so every agent turn answered 400 "auto" tool choice requires --enable-auto-tool-choice and --tool-call-parser to be set. Devstral Small 2 gets --enable-auto-tool-choice --tool-call-parser=mistral, Nemotron 3 Super --enable-auto-tool-choice --tool-call-parser=qwen3_coder and --reasoning-parser=nemotron_v3 (vLLM’s built-in twin of the model card’s super_v3 plugin), so its thinking is returned as reasoning content.
  • Removed

    • The portal’s app-config carries no agentPlatform.modelManager block (giantswarm/agent-platform#318). The Models pages call model-manager’s x_model-manager_* tools through muster as the signed-in person (giantswarm/backstage#2294, Backstage 2.19.0 on), so the REST apiBaseUrl the chart rendered with model-manager’s route on was read by nothing. verify-wiring asserts it stays out; the muster.installations entry and the model-manager route are unchanged.
  • Fixed

    • (deps) Update module github.com/giantswarm/selfupdate-cosign to v0.3.1 in #1335 by @renovate[bot]

    Full Changelog: https://github.com/giantswarm/muster/compare/v5.32.3...v5.32.4