Repository navigation
Conversation
… instance SharpCache keyed reference-type arguments by GetHashCode(), i.e. object identity. RuleEngine.Triggered builds a new AgentFilter on every call, so every trigger missed and parked another full copy of all agents in the static MemoryCache for 10 minutes (OneBrain pods saw-toothing at 80-88% of their 3 GiB limit). perInstanceCache entries were parked there too, one dead copy per DI scope. - Build argument keys from content: strings (length-prefixed, SHA-256 when long), primitives, ICacheKey, otherwise a SHA-256 of the JSON. An argument without a stable key bypasses the cache instead of falling back to identity. - AgentFilter implements ICacheKey. - perInstanceCache entries live on the instance (ConditionalWeakTable) and are collected with it; ClearCacheAsync still clears them. - Callers that mutated now-shared cached results work on copies: RoutingAgentHook (routable agent fields) and AgentController.GetAgent (inherit). - GetAgent no longer flags the shared AgentSettings.LlmConfig as inherited. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- RoutingAgentHook: one conversation's filled fields are removed from a copy, not from the cached routable agents the next conversation gets. - AgentController.GetAgent: inheriting and resolving redirect names leave the cached agent untouched. - perInstanceCache entries are collected together with their scope, and Utilities.ClearCache still clears them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PR Summary by QodoPrevent SharpCache agent memory growth and shared-result mutations
AI Description
Diagram
High-Level Assessment
Files changed (9)
|
Drop the hand-written AgentFilter.GetCacheKey. The generic SharpCache key already hashes the filter's JSON, which picks up any field added later; a hand-written key silently serves wrong results when a new field is left out, and its field-by-field "_" join let text shift between adjacent free-text fields into the same key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Build each conversation's routable agents with the already-filled fields left out, instead of copying the cached agents and then removing fields from the copies. Same result, one pass, no list mutation. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The key prefix was the method name only, so same-named methods on different classes with equal arguments shared one entry. OneBrain loads both CsvNERDataLoader and OneDbEntityDataLoader, whose argument-less, cached LoadVocabularyAsync() therefore served whichever vocabulary loaded first to both for 60 minutes. The test project now references Rougamo.Fody so tests can weave [SharpCache] onto their own classes; FodyWeavers.xml is generated on build, as for the src projects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
reviewed |
No description provided.