Skip to content

Commit fcb405d

Browse files
EItanyaclaudeCopilot
authored
feat: add context management configuration for agents (kagent-dev#1391)
Add support for event compaction (compression/summarization) and context caching in agents. This enables reducing context size for long conversations while preserving key information. Changes across the full stack: - Go CRD types with optional defaults and kubebuilder validation - Go ADK config types with custom UnmarshalJSON for model polymorphism - Translator logic with mergeDeploymentData for summarizer model support - Python Pydantic models and strongly-typed ADK config builder - UI ContextSection component with compaction/cache toggle controls - Comprehensive tests: golden test, unit tests, marshal/unmarshal tests Also consolidates deployment data merging into a single mergeDeploymentData function, replacing the duplicate inline dedup logic in translateEmbeddingConfig. --------- Signed-off-by: Eitan Yarmush <eitan.yarmush@solo.io> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 9cbe4fe commit fcb405d

24 files changed

Lines changed: 2257 additions & 178 deletions

File tree

go/api/v1alpha2/agent_types.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,59 @@ type DeclarativeAgentSpec struct {
157157
// Memory configuration for the agent.
158158
// +optional
159159
Memory *MemorySpec `json:"memory,omitempty"`
160+
161+
// Context configures context management for this agent.
162+
// This includes event compaction (compression) and context caching.
163+
// +optional
164+
Context *ContextConfig `json:"context,omitempty"`
165+
}
166+
167+
// ContextConfig configures context management for an agent.
168+
type ContextConfig struct {
169+
// Compaction configures event history compaction.
170+
// When enabled, older events in the conversation are compacted (compressed/summarized)
171+
// to reduce context size while preserving key information.
172+
// +optional
173+
Compaction *ContextCompressionConfig `json:"compaction,omitempty"`
174+
}
175+
176+
// ContextCompressionConfig configures event history compaction/compression.
177+
type ContextCompressionConfig struct {
178+
// The number of *new* user-initiated invocations that, once fully represented in the session's events, will trigger a compaction.
179+
// +optional
180+
// +kubebuilder:default=5
181+
// +kubebuilder:validation:Minimum=1
182+
CompactionInterval *int `json:"compactionInterval,omitempty"`
183+
// The number of preceding invocations to include from the end of the last compacted range. This creates an overlap between consecutive compacted summaries, maintaining context.
184+
// +optional
185+
// +kubebuilder:default=2
186+
// +kubebuilder:validation:Minimum=0
187+
OverlapSize *int `json:"overlapSize,omitempty"`
188+
// Summarizer configures an LLM-based summarizer for event compaction.
189+
// If not specified, compacted events are dropped from the context without summarization.
190+
// +optional
191+
Summarizer *ContextSummarizerConfig `json:"summarizer,omitempty"`
192+
// Post-invocation token threshold trigger. If set, ADK will attempt a post-invocation compaction when the most recently
193+
// observed prompt token count meets or exceeds this threshold.
194+
// +optional
195+
TokenThreshold *int `json:"tokenThreshold,omitempty"`
196+
// EventRetentionSize is the number of most recent events to always retain.
197+
// +optional
198+
EventRetentionSize *int `json:"eventRetentionSize,omitempty"`
199+
}
200+
201+
// ContextSummarizerConfig configures the LLM-based event summarizer.
202+
type ContextSummarizerConfig struct {
203+
// ModelConfig is the name of a ModelConfig resource to use for summarization.
204+
// Must be in the same namespace as the Agent.
205+
// If not specified, uses the agent's own model.
206+
// +optional
207+
ModelConfig *string `json:"modelConfig,omitempty"`
208+
// PromptTemplate is a custom prompt template for the summarizer.
209+
// See the ADK LlmEventSummarizer for template details:
210+
// https://github.com/google/adk-python/blob/main/src/google/adk/apps/llm_event_summarizer.py
211+
// +optional
212+
PromptTemplate *string `json:"promptTemplate,omitempty"`
160213
}
161214

162215
// MemorySpec enables long-term memory for an agent.

go/api/v1alpha2/zz_generated.deepcopy.go

Lines changed: 90 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

go/config/crd/bases/kagent.dev_agents.yaml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6196,6 +6196,61 @@ spec:
61966196
minItems: 1
61976197
type: array
61986198
type: object
6199+
context:
6200+
description: |-
6201+
Context configures context management for this agent.
6202+
This includes event compaction (compression) and context caching.
6203+
properties:
6204+
compaction:
6205+
description: |-
6206+
Compaction configures event history compaction.
6207+
When enabled, older events in the conversation are compacted (compressed/summarized)
6208+
to reduce context size while preserving key information.
6209+
properties:
6210+
compactionInterval:
6211+
default: 5
6212+
description: The number of *new* user-initiated invocations
6213+
that, once fully represented in the session's events,
6214+
will trigger a compaction.
6215+
minimum: 1
6216+
type: integer
6217+
eventRetentionSize:
6218+
description: EventRetentionSize is the number of most
6219+
recent events to always retain.
6220+
type: integer
6221+
overlapSize:
6222+
default: 2
6223+
description: The number of preceding invocations to include
6224+
from the end of the last compacted range. This creates
6225+
an overlap between consecutive compacted summaries,
6226+
maintaining context.
6227+
minimum: 0
6228+
type: integer
6229+
summarizer:
6230+
description: |-
6231+
Summarizer configures an LLM-based summarizer for event compaction.
6232+
If not specified, compacted events are dropped from the context without summarization.
6233+
properties:
6234+
modelConfig:
6235+
description: |-
6236+
ModelConfig is the name of a ModelConfig resource to use for summarization.
6237+
Must be in the same namespace as the Agent.
6238+
If not specified, uses the agent's own model.
6239+
type: string
6240+
promptTemplate:
6241+
description: |-
6242+
PromptTemplate is a custom prompt template for the summarizer.
6243+
See the ADK LlmEventSummarizer for template details:
6244+
https://github.com/google/adk-python/blob/main/src/google/adk/apps/llm_event_summarizer.py
6245+
type: string
6246+
type: object
6247+
tokenThreshold:
6248+
description: |-
6249+
Post-invocation token threshold trigger. If set, ADK will attempt a post-invocation compaction when the most recently
6250+
observed prompt token count meets or exceeds this threshold.
6251+
type: integer
6252+
type: object
6253+
type: object
61996254
deployment:
62006255
properties:
62016256
affinity:

go/go.mod

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ require (
1616
github.com/jedib0t/go-pretty/v6 v6.7.8
1717
github.com/kagent-dev/kmcp v0.2.6
1818
github.com/kagent-dev/mockllm v0.0.5
19-
github.com/modelcontextprotocol/go-sdk v1.2.0
19+
github.com/modelcontextprotocol/go-sdk v1.4.0
2020
github.com/muesli/reflow v0.3.0
2121
github.com/pgvector/pgvector-go v0.3.0
2222
github.com/prometheus/client_golang v1.23.2
@@ -67,6 +67,7 @@ require (
6767
github.com/openai/openai-go/v3 v3.16.0 // indirect
6868
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
6969
github.com/sahilm/fuzzy v0.1.1 // indirect
70+
github.com/segmentio/encoding v0.5.3 // indirect
7071
github.com/tidwall/gjson v1.18.0 // indirect
7172
github.com/tidwall/match v1.2.0 // indirect
7273
github.com/tidwall/pretty v1.2.1 // indirect
@@ -106,7 +107,7 @@ require (
106107
github.com/go-openapi/swag v0.23.1 // indirect
107108
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
108109
github.com/goccy/go-json v0.10.5 // indirect
109-
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
110+
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
110111
github.com/google/btree v1.1.3 // indirect
111112
github.com/google/cel-go v0.26.1 // indirect
112113
github.com/google/gnostic-models v0.7.0 // indirect
@@ -165,7 +166,7 @@ require (
165166
golang.org/x/crypto v0.47.0 // indirect
166167
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
167168
golang.org/x/net v0.48.0 // indirect
168-
golang.org/x/oauth2 v0.31.0 // indirect
169+
golang.org/x/oauth2 v0.34.0 // indirect
169170
golang.org/x/sync v0.19.0 // indirect
170171
golang.org/x/sys v0.40.0 // indirect
171172
golang.org/x/term v0.39.0 // indirect

go/go.sum

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,8 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L
121121
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
122122
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
123123
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
124-
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
125-
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
124+
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
125+
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
126126
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
127127
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
128128
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
@@ -214,8 +214,8 @@ github.com/mattn/go-localereader v0.0.2-0.20220822084749-2491eb6c1c75/go.mod h1:
214214
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
215215
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
216216
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
217-
github.com/modelcontextprotocol/go-sdk v1.2.0 h1:Y23co09300CEk8iZ/tMxIX1dVmKZkzoSBZOpJwUnc/s=
218-
github.com/modelcontextprotocol/go-sdk v1.2.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
217+
github.com/modelcontextprotocol/go-sdk v1.4.0 h1:u0kr8lbJc1oBcawK7Df+/ajNMpIDFE41OEPxdeTLOn8=
218+
github.com/modelcontextprotocol/go-sdk v1.4.0/go.mod h1:Nxc2n+n/GdCebUaqCOhTetptS17SXXNu9IfNTaLDi1E=
219219
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
220220
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
221221
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -271,6 +271,8 @@ github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA=
271271
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
272272
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
273273
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
274+
github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w=
275+
github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
274276
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
275277
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
276278
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
@@ -374,8 +376,8 @@ golang.org/x/mod v0.31.0 h1:HaW9xtz0+kOcWKwli0ZXy79Ix+UW/vOfmWI5QVd2tgI=
374376
golang.org/x/mod v0.31.0/go.mod h1:43JraMp9cGx1Rx3AqioxrbrhNsLl2l/iNAvuBkrezpg=
375377
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
376378
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
377-
golang.org/x/oauth2 v0.31.0 h1:8Fq0yVZLh4j4YA47vHKFTa9Ew5XIrCP8LC6UeNZnLxo=
378-
golang.org/x/oauth2 v0.31.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
379+
golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw=
380+
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
379381
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
380382
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
381383
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -390,8 +392,8 @@ golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
390392
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
391393
golang.org/x/time v0.13.0 h1:eUlYslOIt32DgYD6utsuUeHs4d7AsEYLuIAdg7FlYgI=
392394
golang.org/x/time v0.13.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
393-
golang.org/x/tools v0.40.0 h1:yLkxfA+Qnul4cs9QA3KnlFu0lVmd8JJfoq+E41uSutA=
394-
golang.org/x/tools v0.40.0/go.mod h1:Ik/tzLRlbscWpqqMRjyWYDisX8bG13FrdXp3o4Sr9lc=
395+
golang.org/x/tools v0.41.0 h1:a9b8iMweWG+S0OBnlU36rzLp20z1Rp10w+IY2czHTQc=
396+
golang.org/x/tools v0.41.0/go.mod h1:XSY6eDqxVNiYgezAVqqCeihT4j1U2CCsqvH3WhQpnlg=
395397
gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0=
396398
gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY=
397399
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=

0 commit comments

Comments
 (0)