Files
Agent-Native/runtime/reminders/reminders.go
T
weichen 6ddd3da8df Enable canonical versioned Go module consumption
Why: Allow consumers to download an immutable module revision without nested source checkouts or local path replacements.

Evidence: SELF package tests and the prior canonical-path rejection are recorded in the Dev dependency-workspace task card; remote consumption is replayed against the committed candidate.

Impact: Change the module identity and its Go imports while preserving API behavior. Existing historical submodule revisions remain buildable.

Refs: Versioned dependencies U1/U3; feature/dependency-workspace
2026-10-13 15:36:10 +00:00

98 lines
2.2 KiB
Go

// Package reminders 收集一轮里要带给模型的提醒,并做节流。
// 提醒并入最后一条工具结果或用户消息,不另起一条 user 消息。
package reminders
import (
"strings"
"sync"
"time"
"git-ssh.u1680832.nyat.app/weichen/Agent-Native.git/runtime/llm"
)
type Kind string
const (
KindTodo Kind = "todo"
KindPlan Kind = "plan"
KindBackground Kind = "background"
KindDeliverable Kind = "deliverable"
KindBudget Kind = "budget"
)
// Note 是一条待投递的提醒。Key 相同的提醒在本轮只投递一次。
type Note struct {
Kind Kind
Key string
Text string
}
// Bus 按最小间隔、每 run 上限和去重决定是否投递。
type Bus struct {
mu sync.Mutex
minGap time.Duration
cap int
sent int
last time.Time
seen map[string]struct{}
}
func New(minGap time.Duration, cap int) *Bus {
if cap <= 0 {
cap = 3
}
return &Bus{minGap: minGap, cap: cap, seen: map[string]struct{}{}}
}
// Admit 在通过节流时返回真。同一 Kind+Key 只通过一次。
func (b *Bus) Admit(n Note, now time.Time) bool {
if b == nil {
return false
}
b.mu.Lock()
defer b.mu.Unlock()
if b.sent >= b.cap {
return false
}
if b.minGap > 0 && !b.last.IsZero() && now.Sub(b.last) < b.minGap {
return false
}
key := string(n.Kind) + "\n" + n.Key
if _, ok := b.seen[key]; ok {
return false
}
b.seen[key] = struct{}{}
b.last = now
b.sent++
return true
}
// Attach 把提醒正文并入最后一条工具结果或用户消息。
// 找不到这两种消息时原样返回,不追加 user 消息。
func Attach(messages []llm.Message, texts []string) []llm.Message {
var lines []string
for _, text := range texts {
text = strings.TrimSpace(text)
if text != "" {
lines = append(lines, text)
}
}
if len(lines) == 0 || len(messages) == 0 {
return messages
}
block := "<system-reminder>\n" + strings.Join(lines, "\n") + "\n</system-reminder>"
out := append([]llm.Message{}, messages...)
for i := len(out) - 1; i >= 0; i-- {
if out[i].Role != llm.RoleTool && out[i].Role != llm.RoleUser {
continue
}
if out[i].Content != "" {
out[i].Content += "\n" + block
} else {
out[i].Content = block
}
return out
}
return messages
}