Bound agent result cache

This commit is contained in:
Ollie Agent 2026-08-18 06:55:25 +02:00
parent 062642dfd3
commit 6c1de81cf9
2 changed files with 52 additions and 3 deletions

View File

@ -36,7 +36,7 @@ type Agent struct {
closed atomic.Bool
actionMu sync.Mutex // serializes action registration with shutdown
warnedContext bool
resultCache sync.Map
resultCache resultCache
// Execution state — owned by the agent, protected by stateMu.
state string // "idle", "thinking", "calling: <tool>"

View File

@ -43,6 +43,56 @@ type cachedResult struct {
Size int64 // file size at cache time; -1 if no file
}
const (
resultCacheMaxEntries = 256
resultCacheMaxBytes = 32 * 1024 * 1024
)
type resultCache struct {
mu sync.Mutex
items map[string]cachedResult
bytes int
}
func (c *resultCache) Load(key string) (cachedResult, bool) {
c.mu.Lock()
defer c.mu.Unlock()
v, ok := c.items[key]
return v, ok
}
func (c *resultCache) Delete(key string) {
c.mu.Lock()
defer c.mu.Unlock()
if v, ok := c.items[key]; ok {
c.bytes -= len(v.Result)
delete(c.items, key)
}
}
func (c *resultCache) Store(key string, value cachedResult) {
c.mu.Lock()
defer c.mu.Unlock()
if c.items == nil {
c.items = make(map[string]cachedResult)
}
if old, ok := c.items[key]; ok {
c.bytes -= len(old.Result)
}
if len(value.Result) > resultCacheMaxBytes {
return
}
c.items[key] = value
c.bytes += len(value.Result)
for len(c.items) > resultCacheMaxEntries || c.bytes > resultCacheMaxBytes {
for k, v := range c.items {
delete(c.items, k)
c.bytes -= len(v.Result)
break
}
}
}
// extractFilePath attempts to pull a "path" field from JSON tool args.
func extractFilePath(args json.RawMessage) string {
var m map[string]json.RawMessage
@ -533,8 +583,7 @@ func (ag *Agent) execOne(ctx context.Context, call backend.ToolCall) (toolResult
readSafe := rt.ToolMeta[call.Name].Scope == "read"
if readSafe {
key := call.Name + "\x00" + string(call.Arguments)
if v, ok := resultCache.Load(key); ok {
entry := v.(cachedResult)
if entry, ok := resultCache.Load(key); ok {
if cacheValid(entry, call.Arguments) {
ag.emit(Event{Role: "tool", Name: call.Name, Content: entry.Result, OutputFormat: toolOutputFormat(rt, call.Name)})
return toolResult{ToolCallID: call.ID, Name: call.Name, Content: entry.Result}, false