AI Agents

  • Changed

    • The serving preset catalog is published wherever the connectivity chart runs, model serving off included (giantswarm/agent-platform#847). The ServingPreset ConfigMaps (agent-platform.giantswarm.io/serving-preset=true, with the agent-platform.giantswarm.io/chart-version annotation) render in the release namespace whether or not components.modelServing.enabled is set, from the same catalog (files/model-serving/presets/*.yaml plus modelServing.presets, shippedPresets.enabled / .exclude honoured), so model-manager’s check_fit answers a preset’s declaration before a GPU pool and its backend exist. The chat-template ConfigMaps, the discovery ConfigMap and every serving workload stay behind the switch; with it on the render is unchanged. make verify-preset-catalog asserts both sides.
  • Fixed

    • The kagent controller GRPCRoutes match grpc.health.v1.Health (giantswarm/agent-platform#844). The kagent CLI pointed at the edge (--api-url https://agentgateway.<domain>:8443) checks reachability with the gRPC health service, which the controller registers; without a match the call fell into the MCP catch-all (mcp: client must accept both application/json and text/event-stream). Both routes, the data-plane kagent-controller and the edge kagent-controller-public, carry one service-only match for it next to kagent.controllerRoute.grpc.services; make verify-kagent-route asserts it on both.
  • Added

    • networkPolicy.mcpBackends: an in-cluster MCP backend reachable only through muster. A backend an installation registers with muster behind a ClusterIP admits every pod on the cluster unless something restricts it, and a direct call skips muster’s sign-in, audit trail and toolset scoping. Each entry (namespace, ports, optional podSelector, metrics, additionalPeers) renders agent-platform-connectivity-mcp-backend-<key> in the backend’s namespace, in the resolved flavour: on the entry’s ports it admits muster from the release namespace, networkPolicy.mcpBackendScrapers when metrics: true (default: alloy-metrics in kube-system) and the entry’s additionalPeers (e.g. the gateway in front of a backend with a public route); on every port it admits the namespace’s own pods; in the cilium flavour it also admits the kubelet’s probes (the host entity) on every port, since a backend may probe on another port than it serves. It is the ingress counterpart of networkPolicy.musterInClusterMcpPorts. make verify-mcp-backend-netpol asserts both flavours, and that nothing renders without entries or with networkPolicy.enabled: false.
  • Added

    • The CLI sign-in can print the URL instead of opening a browser, and honors $BROWSER. A sign-in always launched the platform opener (xdg-open, open, start) and printed the URL only when the opener failed, so a session driving its own browser never saw the URL. --no-browser on the login command, or MUSTER_NO_BROWSER=1 for every command that signs in, starts no browser process: the authorization URL goes to stdout and the CLI keeps waiting for the callback until the URL is opened elsewhere on the machine. Otherwise the commands in $BROWSER are tried before the platform default. (#1425)
  • Fixed

    • filter_tools names the servers a sign-in would unlock. An agent that discovers tools with filter_tools — where muster’s own list_tools description and the platform’s agent prompts steer it — never learned that a Connector exists until the person had signed in to it: for a server the session is not connected to, the filter returned no tool and no hint, the agent answered “I have no Slack tool”, and the gateway’s Connect button, rendered from a core_auth_login result, never appeared; only list_tools reported servers_requiring_auth. filter_tools now carries servers_requiring_auth too, in list_tools’ shape (name, status, auth_tool, tool_prefix, family), narrowed to the servers whose tools the pattern could match once they are listed: every pending server without a pattern or under *slack*, slack alone under x_slack_*, none under core_* (so list_core_tools is unchanged). The toolset does not narrow it — toolset_requiring_auth still names the part of the toolset a sign-in would unlock — nor do query, description_filter and labels, which have no text to match before the sign-in; the list is sorted by name, as list_tools’ now is. An empty catalogue with such a server answers the structured page instead of No tools available to filter. The tool’s description says so, and the muster CLI’s filter listing prints the servers as its tool listing does. (#1351)
  • Added

    • A serving preset declares the GPU generation it runs natively on: requirements.minComputeCapability (giantswarm/agent-platform#832). The ServingPreset contract gains the key (a CUDA compute capability such as "8.9"), and every shipped preset declares it: 8.9 for the FP8 recipes (qwen3-5-9b-fp8, gemma-4-31b, muse-glimmer-30b, qwen3-6-35b-a3b, devstral-small-2, kolibri-1) and for the two NVFP4 recipes proven on the L40S through vLLM’s Marlin weight-only FP4 path (qwen3-8-27b-l40s, mistral-small-4); 10.0 for the recipes tuned on a Blackwell node (nemotron-3-super-nvfp4, qwen3-8-27b, qwen3-8-flash-next-nvfp4); 8.0 for the bf16-activation recipes (qwen3-5-4b, qwen3-5-4b-hf, gemma-4-12b, gpt-oss-20b, gpt-oss-120b). An FP8 W8A8 checkpoint on an A10G (Ampere, 8.6) goes Ready and answers wrong through vLLM’s weight-only FP8 Marlin fallback while the memory fit says it hosts (giantswarm/model-manager#264); cluster-manager’s form fit reads the declared floor to refuse such a pool (giantswarm/cluster-manager#178), model-manager keeps judging from the checkpoint. make verify-preset-weights holds the declared floor at or above what the checkpoint’s quantization and dtype need (config.json, params.json for the mistral format, hf_quant_config.json for ModelOpt mixed precision; a CUTE_DSL_ARCH pin to Blackwell needs 10.0), with tests/fixtures/serving-preset-floor-understated.yaml as the negative control; a values preset without the key is judged on memory alone.
  • Added

    • components.gateway-api-crds: the Gateway API CRDs for a cluster that has none (giantswarm/cluster-manager#183). The fleet’s gateway-api-crds chart (>=1.9.1 <2.0.0, 1.9.1 is Gateway API v1.6.1, standard channel) into kube-system, off by default: a management cluster runs it as its own app. The connectivity release and agentgateway dependsOn it, so on a workload cluster without the Gateway API the models Gateway and its routes install after the CRDs instead of failing on the missing kinds; off, the reference is dropped. cluster-manager turns it on in the serving slice of such a cluster. The customer BOM pins 1.9.1.
  • Fixed

    • A token-forwarding session survives a fresh token its backend refuses on a pooled connection. Right after the identity provider rotated its signing key, a gateway that has not yet fetched the new key answers a new login’s token with 401 on every request of the session’s connection, not only on the connect the fresh-token handling covered: the capability poll’s re-listing logged “failed to list tools … authorization required” and was not retried, and a tool call retired the session’s authentication and asked the person to sign in to muster again although the login was valid. Such a 401 (a token issued within the 6-minute JWKS window, naming no cause but a key) is now judged on the token the request presented, as on a connect: a tool call keeps the session’s connection and gets a transient error to retry shortly, and muster re-lists the session’s capabilities on its own on the short backoff (15 s doubling to 2 min) until the backend accepts the token. A 401 for an older token, or one naming another cause, keeps today’s handling. (#1429)
  • Changed

    • (ssetest) Close a held stream between Reads without deadlock in #1421 by @teemow

    Fixed

    • (deps) Update module github.com/giantswarm/mcp-oauth to v1.7.0 in #1362 by @renovate[bot]
    • (deps) Update opentelemetry-go monorepo to v1.47.0 in #1406 by @renovate[bot]
    • (workflow) Leave a skipped forEach iteration without an indexed result in #1412 by @marians
    • (workflow) Put a failed step’s error on its own entry only in #1414 by @marians
    • (alerts) MusterMCPServerFlapping ignores a single outage burst in #1417 by @teemow
    • (workflow) A parallel group’s Go error outranks an IsError sibling in #1418 by @teemow
    • (oauth) Document that a session grant is the forwarded principal’s in #1419 by @teemow
    • (test) Hand muster serve its listeners as inherited fds in #1422 by @teemow
    • (test) API server proxy serves its reserved listener in #1424 by @teemow
    • (deps) Update module go.opentelemetry.io/otel/exporters/prometheus to v0.69.0 in #1427 by @renovate[bot]
    • (deps) Update aws sdk in #1428 by @renovate[bot]

    Full Changelog: https://github.com/giantswarm/muster/compare/v5.37.1...v5.37.2

  • Fixed

    • The kagent WorkerPool runs the Substrate release the atelet runs: components.substrate{,-crds}.versionRange is >=1.3.1 <1.4.0 (was >=1.3.0 <1.4.0) (giantswarm/substrate#105). The worker image follows the range’s floor, so a 1.3.1 control plane ran beside the 1.3.0 worker; the floor moves the pool onto ateom-gvisor:1.3.1, which bounds the golden actor’s crash restarts during a pool roll and reaps the leftover runsc children.