Tool runner: the cap's reason fails the call; the test proves the ending; the refused-answer limit keys on the caller's prefix and forgets old entries (issue 1966, review round 1)

Claude-Session: https://claude.ai/code/session_01NcbgfFfQ4Z9UE5jK32PmE5
This commit is contained in:
2026-11-09 13:59:13 +01:00
parent f3a9cc276e
commit 312e29478e
4 changed files with 73 additions and 27 deletions
+13 -3
View File
@@ -1229,15 +1229,25 @@ func (c *Conn) answerRefused(err error) bool {
if len(m) < 2 || !strings.HasPrefix(strings.Trim(m[1], `"`), "_INBOX.") {
return false
}
// Keyed without the reply's last token (a new one per request), so a caller's burst is one line.
subject := strings.Trim(m[1], `"`)
if dot := strings.LastIndex(subject, "."); dot > len("_INBOX.") {
subject = subject[:dot]
}
c.mu.Lock()
if c.inboxSaid == nil {
c.inboxSaid = map[string]time.Time{}
}
last, seen := c.inboxSaid[subject]
say := !seen || time.Since(last) >= time.Minute
now := time.Now()
for k, at := range c.inboxSaid {
if now.Sub(at) >= time.Minute {
delete(c.inboxSaid, k)
}
}
_, seen := c.inboxSaid[subject]
say := !seen
if say {
c.inboxSaid[subject] = time.Now()
c.inboxSaid[subject] = now
}
c.mu.Unlock()
if say && c.Logf != nil {