feat(adk): honour spec.declarative.context.compaction in the Go runtime (backport to release/v0.10.x) - #2791
Conversation
ADK v2.3.0 ships native context compaction (session/compaction: sliding window, tail retention, LLM summarizer) and the runner hook that applies it. The OpenTelemetry exporters and contrib instrumentation move to the matching v1.45.0 / v0.21.0 / v0.70.0 set, which the new ADK version already requires for otel/log. Signed-off-by: Timo Derstappen <teemow@gmail.com>
The controller compiles spec.declarative.context.compaction into the agent's config.json (context_config.compaction) and the Python runtime consumes it, but the Go runtime never read it: a Go agent, the CRD default since 0.10.0, grew its prompt with every turn no matter what the operator configured, and the only signal was the UnsupportedFeatures condition. The runner now receives a compaction.Config derived from the agent config: - compactionInterval and overlapSize drive ADK's sliding window, tokenThreshold and eventRetentionSize its tail retention. Either strategy is off when its settings are unset, so an agent without context.compaction runs exactly as before. - A setting whose partner is missing (tokenThreshold without eventRetentionSize, and the reverse; overlapSize without an interval) is ignored with a warning, the way the Python runtime treats a half-configured tail retention. What remains is validated at startup with the runner's own rules, so a configuration the runner would refuse fails fast with the reason instead of on the first turn. - summarizer.modelConfig builds an LLM summarizer through the same model factory as the agent, with the model's generation config and a 60s bound per call. summarizer.promptTemplate gets the tool-name instruction the Python runtime appends, so summaries keep namespaced tool names; a template without a summarizer model runs on the agent's own model. Without either, the runner summarizes with the agent's model and ADK's default prompt. - Startup logs whether compaction is configured and with which values, so an operator can see it from the agent's log. Compaction records travel on EventActions.Compaction, which both the controller-backed and the local session store persist as a whole, so a summary survives a restart. The reconciler no longer reports context compaction as unsupported on the Go runtime, and the CRD description no longer claims that compacted events are dropped without a summarizer: on both runtimes the agent's own model summarizes by default. tokenThreshold documents that it takes effect together with eventRetentionSize, which both runtimes require. Signed-off-by: Timo Derstappen <teemow@gmail.com>
There was a problem hiding this comment.
🟡 Changes recommended
The backport updates additional direct dependencies beyond what the PR description scopes/justifies, which should be confirmed as required (or reduced) to keep release-branch risk controlled.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Backports Go-runtime support for spec.declarative.context.compaction to release/v0.10.x, wiring the Agent CRD’s compaction settings through to the Google ADK v2 runner so Go declarative agents can compact session history (and the controller no longer reports compaction as unsupported).
Changes:
- Upgrade
google.golang.org/adk/v2to v2.3.0 and align related telemetry dependencies. - Add Go runtime translation of
context_config.compactioninto ADK runnerCompactionconfiguration (incl. optional summarizer model/prompt handling) plus unit tests. - Update controller feature validation and CRD text to reflect compaction support and correct summarizer/token-threshold documentation.
File summaries
| File | Description |
|---|---|
| helm/kagent-crds/templates/kagent.dev_sandboxagents.yaml | CRD helm template doc fixes for compaction summarizer + tokenThreshold semantics. |
| helm/kagent-crds/templates/kagent.dev_agents.yaml | CRD helm template doc fixes for compaction summarizer + tokenThreshold semantics. |
| go/go.mod | Bumps ADK + OTel deps; also bumps several other direct deps. |
| go/go.sum | Updated checksums for the dependency upgrades. |
| go/core/internal/controller/reconciler/runtime_features_test.go | Adds coverage to ensure compaction is no longer flagged unsupported for Go runtime. |
| go/core/internal/controller/reconciler/reconciler.go | Stops reporting context compaction as unsupported for Go declarative agents. |
| go/api/v1alpha2/agent_types.go | Updates CRD field comments for summarizer default + tokenThreshold/eventRetentionSize coupling. |
| go/api/config/crd/bases/kagent.dev_sandboxagents.yaml | Regenerated CRD base with updated compaction docs. |
| go/api/config/crd/bases/kagent.dev_agents.yaml | Regenerated CRD base with updated compaction docs. |
| go/adk/pkg/runner/adapter.go | Passes computed compaction config into ADK runner config. |
| go/adk/pkg/README.md | Updates package overview to mention context compaction wiring. |
| go/adk/pkg/agent/compaction.go | Implements translation from agent config compaction settings to ADK compaction config + summarizer creation/logging. |
| go/adk/pkg/agent/compaction_test.go | Adds unit tests for strategy mapping and runner behavior with compaction enabled. |
Review details
- Files reviewed: 12/13 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| github.com/a2aproject/a2a-go v0.3.15 | ||
| github.com/a2aproject/a2a-go/v2 v2.3.1 | ||
| github.com/a2aproject/a2a-go/v2 v2.5.0 | ||
| github.com/abiosoft/ishell/v2 v2.0.2 | ||
| github.com/anthropics/anthropic-sdk-go v1.61.0 | ||
| github.com/aws/aws-sdk-go-v2/config v1.32.31 | ||
| github.com/aws/aws-sdk-go-v2/config v1.32.35 |
There was a problem hiding this comment.
These are not hand-picked bumps: go get google.golang.org/adk/v2@v2.3.0 raised them to the minimum versions ADK v2.3.0 requires (MVS), and go mod tidy kept them. From go mod graph on this branch:
github.com/a2aproject/a2a-go/v2@v2.5.0← required bygoogle.golang.org/adk/v2@v2.3.0(its go.mod:require github.com/a2aproject/a2a-go/v2 v2.5.0)github.com/aws/aws-sdk-go-v2/config@v1.32.35← required bygithub.com/openai/openai-go/v3@v3.52.0, which ADK v2.3.0 requires
Reverting either would put the module below what ADK v2.3.0 needs and go mod tidy would raise it again. main did not show these hunks only because its go.mod was already at these versions. I have listed the full set with the reason in the PR description under "Dependency".
| github.com/kagent-dev/kmcp v0.3.0 | ||
| github.com/kagent-dev/mockllm v0.0.5 | ||
| github.com/modelcontextprotocol/go-sdk v1.6.1 | ||
| github.com/modelcontextprotocol/go-sdk v1.7.0 | ||
| github.com/muesli/reflow v0.3.0 | ||
| github.com/openai/openai-go/v3 v3.46.0 | ||
| github.com/openai/openai-go/v3 v3.52.0 |
There was a problem hiding this comment.
Same cause as above: google.golang.org/adk/v2@v2.3.0 requires github.com/modelcontextprotocol/go-sdk v1.7.0 and github.com/openai/openai-go/v3 v3.52.0 directly (both listed in its go.mod; v2.1.0 required v1.4.1 and v3.8.1), plus google.golang.org/genai v1.69.0 and google.golang.org/protobuf v1.36.12. They cannot be reverted while staying on ADK v2.3.0, which is the version that ships the compaction primitives this change consumes. Documented in the PR description now.
EItanya
left a comment
There was a problem hiding this comment.
Same comment as the branch on main, can you add an e2e test with mockllm as the summarizer?
Backport of #2790 to
release/v0.10.x. This is the branch where the field exists on the Agent CRD and the reconciler flagged it, so it carries two thingsmaincannot: the reconciler no longer reports compaction as unsupported on the Go runtime, and the CRD description is corrected.Problem
As of 0.10.0 the Agent CRD defaults
spec.declarative.runtimetogo, and the Go runtime never readspec.declarative.context.compaction. The controller compiled the field into the agent'sconfig.json(context_config.compaction,translator/agent/compiler.go) and the Python runtime consumed it, but a Go agent grew its prompt with every turn regardless of what the operator configured; the only signal was theUnsupportedFeaturescondition (#2728). Measured on an internal installation running 0.10.1: an agent session grew from 4k to 190k input tokens per model call over 119 calls, and every Go agent there ran without compaction because the runtime ignored the field.google.golang.org/adk/v2v2.3.0 (2026-08-31) ships native compaction (session/compaction: sliding window, tail retention, LLM summarizer) and therunner.Config.Compactionhook, so the runtime consumes that instead of carrying its own port of the algorithm, which is what #1971 and #2025 attempted before the primitives existed.Change
google.golang.org/adk/v2v2.1.0 → v2.3.0. The OpenTelemetry exporters and contrib instrumentation move to the matching v1.45.0 / v0.21.0 / v0.70.0 set, which the new ADK version requires forotel/log.go get google.golang.org/adk/v2@v2.3.0also raises the direct requirements that ADK v2.3.0 pins higher than this branch had (minimum version selection, nothing bumped by hand):github.com/a2aproject/a2a-go/v2v2.3.1 → v2.5.0,github.com/modelcontextprotocol/go-sdkv1.6.1 → v1.7.0,github.com/openai/openai-go/v3v3.46.0 → v3.52.0,google.golang.org/genaiv1.65.0 → v1.69.0,google.golang.org/protobuf→ v1.36.12, and throughopenai-gov3.52.0github.com/aws/aws-sdk-go-v2/configv1.32.31 → v1.32.35 (go mod graphnames ADK v2.3.0 as the requirer of each).mainis already at these versions, which is why feat(adk): honour context compaction in the Go runtime #2790 shows only the ADK and OpenTelemetry hunks. No kagent code needed changes for the bump; the v2.2.0 and v2.3.0 release notes carry no breaking changes for the packages kagent imports, and the fullmake -C go testpasses on the branch.agent.CompactionConfigtranslatescontext_config.compactioninto acompaction.Configandrunner.CreateRunnerConfighands it to the ADK runner.compactionInterval/overlapSizedrive the sliding window,tokenThreshold/eventRetentionSizetail retention; either strategy is off when its settings are unset, so an agent withoutcontext.compactionruns exactly as before.tokenThresholdwithouteventRetentionSize(and the reverse),overlapSizewithout an interval. That mirrors the Python runtime, where adk-python runs tail retention only when both settings are present. What remains is validated at startup with the runner's own rules, so a configuration the runner would refuse (negative values, no strategy at all) fails fast with the reason instead of on the first turn.summarizer.modelConfigbuilds acompaction.LLMSummarizerthrough the same model factory as the agent (CreateLLM), with the model's generation config and a 60 s bound per call (the same bound the runner applies to its default summarizer).summarizer.promptTemplategets the tool-name instruction the Python runtime appends (fix(compaction): preserve namespaced tool names in LLM summarizer prompt #1907), so summaries keep namespaced tool names; a template without a summarizer model runs on the agent's own model. With neither, the runner summarizes with the agent's model and ADK's default prompt, matching the Python runtime.Context compaction enabledwith the resolved values and the summarizer model, orContext compaction not configured, so an operator can see from the agent log what the runtime does with the field.validateRuntimeFeaturesdrops the "context compression/compaction (not implemented in Go runtime)" entry;executeCodeBlocksis still reported.summarizerdescription claimed compacted events are dropped without summarization; on both runtimes the agent's own model summarizes by default.tokenThresholddocuments that it takes effect together witheventRetentionSize, which both runtimes require. Regenerated withmake controller-manifests.Compaction records travel on
EventActions.Compaction; both the controller-backed session service (json.Marshalof the whole event) and the local DurableDir store (ADK'ssession/database) persistActionsas a whole, so a summary survives a restart and the same range is not summarized again.Testing
go test ./adk/pkg/agent/:TestCompactionStrategies(table: each strategy alone and combined, unset settings, the three half-configured cases, no strategy, negative values),TestCompactionConfig(not configured → nil; default summarizer; dedicated summarizer model; custom prompt on the agent model; prompt without{conversation_history}rejected; prompt without any model rejected; thecontext_configblock as the controller compiles it),TestCompactionSlidingWindowFiresAfterInterval(a scripted model drives the ADK runner: no record after turn 1, one record after turn 2 whose content is the summarizer's reply, and turn 3's request shows the summary and none of the compacted turns),TestCompactionTailRetentionFiresOverTokenThreshold.go test ./core/internal/controller/reconciler/:TestValidateRuntimeFeatures(compaction on go / default / python raises nothing;executeCodeBlocksstill does, without mentioning compaction).make -C go test: passes (52 packages,-race).make -C go lintcrashes on this branch inside staticcheck'sbuildirwhile analysing the standard library packageinternal/pollwith the local Go 1.27 toolchain, independent of this change; withstaticcheckandunuseddisabled the touched packages (adk/pkg/agent,adk/pkg/runner,core/internal/controller/reconciler,api/v1alpha2) report 0 issues. CI runs the full linter.End-to-end (kind, images from this branch, real model)
kagent 0.10.1 chart in a kind cluster with the controller and
golang-adkimages built from this branch;default-model-configis Anthropicclaude-haiku-4-5. Two identical Go agents with the k8s tools (k8s_get_resources,k8s_get_resource_yaml,k8s_describe_resource,k8s_get_events), one withand one without. Both were driven through the same five-turn conversation over the controller's A2A endpoint with a fixed
contextId(list all pods, the controller deployment YAML, describe the controller pod and its events, the services of the namespace, then a recap "without calling any tool").prompt_token_countper model call as the runtime reports it inadk_usage_metadata:(The jump in turn 3 is the describe-plus-events tool result, about 41k tokens on both agents.) The two
EventActions.Compactionrecords are stored in the session and come back throughGET /api/sessions/{id}, each covering exactly the two invocations of its window. The summaries were written by the dedicated summarizer ModelConfig and carry the "Durable facts" section of ADK's default prompt: controller image and digest, port 8083/TCP, probes, resource limits, the LoadBalancer comparison. The recap in turn 5 answered from the summaries with the controller image, digest, port and service comparison intact; the per-pod list from turn 1 came back as a count per namespace, which is the recall trade-off ADK documents for summaries.Before the upgrade the 0.10.1 controller reported on the same Agent:
After the upgrade the condition is gone (
Accepted=True,Ready=True), and the agent log shows at startupand
Context compaction not configuredfor the agent without the field. ThetokenThreshold/eventRetentionSizestrategy was not exercised end to end; it is covered byTestCompactionTailRetentionFiresOverTokenThreshold.Closes #2728.