AI Agents

  • Changed

    • (deps) Update gsoci.azurecr.io/giantswarm/agent-manager docker tag to v1.1.3 in #397 by @renovate[bot]

    Full Changelog: https://github.com/giantswarm/agent-platform/compare/v4.7.15...v4.7.16

  • Fixed

    • The managers are pinned to the kagent API version the 4.x line serves (giantswarm/agent-platform#401): model-manager.kagent.apiVersion and agent-manager.kagent.apiVersion are v1alpha3 in the meta chart’s values — the managers’ charts default to auto, which discovers the served kagent.dev version once at start-up and bakes it into the client. On an in-place 3.x → 4.x upgrade nothing in model-manager’s values or pod template changed, so its pod never rolled: it kept the v1alpha2 it had discovered under kagent 0.10 while kagent-crds had replaced the CRDs with v1alpha3 only, and every ModelConfig call failed with list ModelConfigs in kagent: the server could not find the requested resource — a pulled model could not be wired until the pod happened to restart (found by the migration rehearsal, giantswarm/agentlab#143, models-test on a lab upgraded in place from 3.23.1 to 4.7.14; agent-manager’s pod rolled only because its chart moved to 1.1.x). Both charts render the key as the container’s --kagent-api-version=v1alpha3, so the pin is the values change that rolls both Deployments on the cut-over, after kagent-crds is Ready (both dependsOn it), and every manager speaks v1alpha3 from its first request. make verify-components asserts the pin in both forwarded release values; verify-components-charts renders both manager charts with the forwarded values and asserts the argument reaches the pod template. UPGRADE.md “3.x → 4.0 (the kagent line)” carries the operator’s side: the managers roll once, nothing to do. No installation acts — the release stays inert behind the fleet’s <4.0.0 bound; an installation already on 4.x sees both managers roll once on the next reconcile.
  • Fixed

    • A connectivity chart release no longer stalls on the completed migrate Job (giantswarm/agent-platform#399). The Job <release>-agent-manager-migrate-<hash> was named with a hash of its image, args and environment so that a changed Job renders under a new name (Job.spec.template is immutable), but its pod template carried labels.common — helm.sh/chart and app.kubernetes.io/version, which change on every chart release while the hash did not — so the next release within the Job’s day-long TTL re-applied the same-named Job with a different immutable template and the apiserver refused it (Job.batch "…-agent-manager-migrate-16c89a3a" is invalid: spec.template: Invalid value: … field is immutable); helm-controller exhausted its retries, rolled the connectivity release back (Stalled=True RetriesExceeded) and every dependant — substrate, kagent, the managers, backstage — read dependency not ready until the TTL removed the Job (found by the migration rehearsal, giantswarm/agentlab#143, on the connectivity release moving 4.7.12 → 4.7.13). Two changes: the pod template carries the stable labels only — app.kubernetes.io/name, app.kubernetes.io/instance, app.kubernetes.io/component: agent-manager-migrate (the network policy’s selector) and the team label (agent-platform.kagent.migration.podLabels); the Job’s own labels keep labels.common — and the Job’s name hashes the whole rendered pod template (agent-platform.kagent.migration.podTemplate: image, args, environment, identity, labels, everything the apiserver makes immutable), so any template change renders a new Job and an unchanged template is re-applied as is; a chart release changes neither. An installation that has the completed Job of an earlier 4.x release (its template carries that release’s version) sees this release render the Job once more under a new name — Helm creates it and removes the old one — and migrate runs again, idempotent (nothing left to rewrite; the contract phase where its gates are met), instead of the refused apply. make verify-migration packages the connectivity chart at two versions and asserts the Job’s name and spec.template are identical while its own labels follow the chart version, and that a changed image tag or identity changes the name. No installation acts — the release stays inert behind the fleet’s <4.0.0 bound; an installation already on 4.x moves to it on the next reconcile, a stalled connectivity release included (a new chart version resets helm-controller’s retries).
  • Fixed

    • The 3.x → 4.x upgrade migrates the storage version of the kagent CRDs, and keeps the hand-created ModelConfigs (giantswarm/agent-platform#396). A cluster that ran kagent 0.10 stores modelconfigs, modelproviderconfigs and remotemcpservers.kagent.dev at v1alpha2; the line’s kagent-crds chart declares v1alpha3 only, the apiserver refuses the CRD update (v1alpha2 was previously a storage version, and must remain in spec.versions until a storage migration …), kagent-crds never installs and the connectivity, substrate and kagent releases behind it never move (found by the migration rehearsal, giantswarm/agentlab#143). Two hook Jobs of the meta chart, as the hook identity in alpine/k8s, rendered whenever components.kagent-crds is on — with the bundled engine and, the one exception to “no hook without the engine”, through a cluster’s own Flux, so the cut-over stays “lift the bound and let Flux upgrade” on every installation: <release>-kagent-storage-version-backup (pre-install,pre-upgrade, weight -7) records every object of each of the three CRDs still stored at v1alpha2 into ConfigMap kagent-storage-version-migration in the kagent namespace (status and the server-set metadata stripped; recorded-at) and deletes those CRDs, so kagent-crds installs them at v1alpha3, then — on every run — re-points the three kinds from kagent.dev/v1alpha2 to v1alpha3 in every Helm release manifest that still names them (the release Secrets, patched in place: what helm mapkubeapis does for a removed API — Helm reads a release’s stored manifest back through the cluster’s REST mappings on each upgrade, and the 3.x connectivity release’s catalog and the kagent 0.x release’s default ModelConfig and tool-server RemoteMCPServer otherwise fail with unable to build kubernetes objects from current release manifest: no matches for kind "RemoteMCPServer" in version "kagent.dev/v1alpha2", as the lab showed); <release>-kagent-storage-version-restore (post-install,post-upgrade, weight 0) waits for modelconfigs.kagent.dev to be Established serving v1alpha3 (up to 8 min — under a cluster’s own Flux the post hooks run before kagent-crds has installed) and re-creates every recorded ModelConfig no Helm release owned at kagent.dev/v1alpha3 with name, namespace, labels, annotations and spec unchanged (the spec is identical in both versions), leaves one that is already present to its owner, fails the upgrade on any other refusal, and marks the ConfigMap restored-at so it runs once (a ModelConfig removed by hand after the cut-over must not come back). The chart-rendered ModelConfigs come back from their releases, model-manager’s from model-manager; RemoteMCPServers and ModelProviderConfigs are recorded, never restored — the 4.x charts render their own. A CRD that is absent or stores v1alpha3 is left alone: a fresh install and a second run change nothing (the ATS smoke sees the hooks do nothing). The hook identity <release>-hooks is created for the hooks’ events too (agent-platform.hooks.serviceAccountEvents composes them) and, without the engine, for those alone. make verify-kagent-storage-version asserts the pair, the scripts, the identity’s events, the engine-off render and the kagent-off render; verify-engine / verify-self carry the family in their expected hook sets. UPGRADE.md “3.x → 4.0 (the kagent line)” has the operator’s side: what comes back and from where, the downtime window, the record and when to delete it.
  • Changed

    • (deps) Update gsoci.azurecr.io/giantswarm/agent-manager docker tag to v1.1.2 in #395 by @renovate[bot]

    Full Changelog: https://github.com/giantswarm/agent-platform/compare/v4.7.11...v4.7.12

  • Changed

    Full Changelog: https://github.com/giantswarm/klaus/compare/v0.1.11...v0.1.12

  • Fixed

    • components.klaus-gateway.versionRange is 1.x (giantswarm/klaus-gateway#234, giantswarm/giantswarm#37705 wave 1c): the 4.x roster still selected 0.x, the klaus-gateway that speaks REST to the 0.10 controller — against this line’s controller GRPCRoute (its klausGateway.a2a.url is already the grpc:// target) a 0.x gateway gets 404s for every REST path. klaus-gateway 1.x is the kagent API v2 client (A2A v1 over gRPC, AgentTemplate discovery, one AgentInstance per thread); the customer BOM pins 1.0.2; make verify-components asserts the range. No installation acts: components.klaus-gateway is off by default, and the one 4.x installation runs its gateway outside the chart. The 3.x meta chart keeps 0.x.
  • Changed

    • The Substrate pin moves to 0.0.27-gs.5 (components.substrate and components.substrate-crds floor, the customer BOM, kagent.substrateWorkerPool.workerImage): gs.3 plus a golden boot whose image the registry refuses failing instead of resuming forever (gs.4, giantswarm/substrate#14 — giantswarm/giantswarm#37742 row 27) and the podcertificate-controller-system namespace kept across an uninstall (gs.5, giantswarm/substrate#13 — #384).

    Fixed

    • A reinstall after helm uninstall brings Agent Substrate up with a consistent trust chain (giantswarm/agent-platform#384). The uninstall took the podcertificate-controller-system namespace and the two CA pools in it with the substrate release while the signers’ cluster-scoped ClusterTrustBundles stayed; the reinstall minted new roots and the podcertificate-controller republished the bundles within seconds, but every Substrate pod had projected the surviving bundle when it started and reads its CA once, at dial time — x509: certificate signed by unknown authority against ate-api-server from ate-controller, atelet and the atenet router, no golden boot (the own-Flux ATS scenario on the cluster the smoke had uninstalled from, PR #380). Two halves: the Substrate line keeps the namespace across an uninstall (helm.sh/resource-policy: keep, 0.0.27-gs.5, giantswarm/substrate#13 — the pin below), and the connectivity bootstrap hook publishes both signers’ ClusterTrustBundles from the pools (server-side, the way it applies actor-id-ca-certs) before the substrate release installs and on every upgrade, so a bundle never reaches a pod with roots its pool does not have; the hook’s ClusterRole gains clustertrustbundles (get, list, watch, create, patch) and attest on the two podcert signers (the apiserver admits a bundle that names a signer only from a client allowed to attest it). The ATS smoke no longer removes Substrate’s leftovers between its scenarios: the own-Flux scenario reinstalls onto the cluster the smoke uninstalled from — the kept namespace, pools and bundles in place — and asserts each signer’s bundle carries its pool’s roots; the smoke asserts what the uninstall leaves.
  • Fixed

    • The Substrate line re-pins to v0.0.27-gs.4 (giantswarm/giantswarm#37757; giantswarm/giantswarm#37742 row 27): the release carries giantswarm/substrate#14 — an actor whose image the registry refuses for good (a digest answered 404, a repository the pull may not read) is crashed with the registry’s answer instead of being resumed against the same reference forever, and ate-api’s ActorTemplate reconciler records the cause on the template. A Harness whose workload.image cannot be pulled therefore fails its golden boot at once as Ready=False ActorTemplateFailed (GoldenActorCrashed: actor … crashed: … MANIFEST_UNKNOWN: manifest unknown) instead of sitting in ActorTemplatePending with a worker pinned for as long as anyone waits (measured at 300 s without a message on gs.2). components.substrate/components.substrate-crds move to >=0.0.27-gs.4 <0.0.28-0 and kagent.substrateWorkerPool.workerImage to …:0.0.27-gs.4; examples/customer-bom.yaml and tests/verify-components.py move with the pin. Asserted end to end in giantswarm/agent’s ATS on the release (test_fail_fast.py::test_unpullable_harness_image_fails_fast: 5 s, giantswarm/agent#34). No installation acts — the release stays inert behind the fleet’s <4.0.0 bound.
  • Fixed

    • A kagent.modelConfigs[] entry’s provider is checked against the ModelConfig CRD’s enum at render time (giantswarm/agent-platform#357): agent-platform.modelConfigProvider fails the render for any other value, naming the entry and the ten providers — Anthropic, OpenAI, AzureOpenAI, Ollama, Gemini, GeminiVertexAI, AnthropicVertexAI, Bedrock, SAPAICore, Foundry, case-sensitive as the CRD’s. Until now provider: openai rendered and the API server refused the object at apply time with the enum error, after the chart had said nothing. The baseUrl already goes under the CRD’s block key through agent-platform.modelConfigBaseUrlKey (#333: anthropic, openAI, sapAICore, the three ModelConfigSpec gives one; the render refuses a baseUrl on the seven others), in templates/kagent/modelconfigs.yaml and the MutatingAdmissionPolicy alike; what was missing was the pin. ci/test-llm-routing-values.yaml carries an OpenAI entry with its own baseUrl, so make verify-kagent-crds validates the openAI key against the kagent line’s CRD on every run — and now sweeps every provider of the CRD’s spec.provider enum, read from the CRD at KAGENT_LINE_REF: each renders, a baseUrl lands under the block the CRD gives one to and nowhere else, the render refuses it where the CRD’s block has none, and a provider outside the enum (a lower-cased spelling included) fails naming the enum; a re-pin that moves the enum or a block’s fields fails the check naming the helper to move with it. make verify-llm-routing asserts the openAI key for an explicit URL and for the routed default with llmRouting.backend.provider: openai, and the enum guard. Lab-proven on agentlab (Kubernetes 1.37, the line’s controller): the fixture’s OpenAI ModelConfig applied as rendered, spec.openAI.baseUrl survived admission and the kagent controller reported Accepted and ResolvedRefs; the same object with the lower-cased openai block lost the field to pruning with a non-strict client and was Accepted all the same (a strict client refuses it as an unknown field) — the silent direct path the issue describes. No installation acts: every valid catalog renders byte-identically; only a render that the API server would have refused fails earlier.