Files
Agent-Native/runtime/memory/write.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

94 lines
3.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package memory
import (
"context"
"encoding/json"
"fmt"
"strings"
"time"
"git-ssh.u1680832.nyat.app/weichen/Agent-Native.git/runtime/tools"
)
// memory_write 工具:模型自服务写回(fail-closed 校验 scope/type/content)。
// 只在宿主配置 Store 时注册(RegisterWrite 由循环在 Run 启动时接线)。
type writeTool struct {
store Store
scope string // 默认 scope(AgentSpec.MemoryScope 驱动;空 = user)
}
var validScopes = map[string]bool{"user": true, "project": true}
var validTypes = map[string]bool{
"fact": true, "preference": true, "decision": true, "episode": true, "procedure": true,
}
// RegisterWrite 把 memory_write 注册进 reg(store nil 时跳过;重复注册按
// 覆盖处理——宿主不得在同一注册表上给不同 run 挂不同实现)。
func RegisterWrite(reg *tools.Registry, store Store, defaultScope string) {
if reg == nil || store == nil {
return
}
reg.Register(&writeTool{store: store, scope: defaultScope})
}
func (t *writeTool) Name() string { return "memory_write" }
func (t *writeTool) Description() string {
return "把一条值得跨会话记住的事实/偏好/决定写入长期记忆(scope: user 或 project;type: fact|preference|decision|episode|procedure)。"
}
func (t *writeTool) Parameters() json.RawMessage {
return json.RawMessage(`{"type":"object","required":["type","content"],"properties":{
"scope":{"type":"string"},
"type":{"type":"string"},
"content":{"type":"string"},
"expires_in_days":{"type":"number"}
}}`)
}
// maxWriteContent 是单条记忆的内容上限(字符)。
const maxWriteContent = 2000
func (t *writeTool) Execute(ctx context.Context, args json.RawMessage) (tools.Result, error) {
var a struct {
Scope string `json:"scope"`
Type string `json:"type"`
Content string `json:"content"`
ExpiresInDays float64 `json:"expires_in_days"`
}
if err := json.Unmarshal(args, &a); err != nil {
return tools.Result{Content: "memory_write: 参数不是完整 JSON 对象", IsError: true}, nil
}
scope := strings.TrimSpace(a.Scope)
if scope == "" {
scope = t.scope
}
if scope == "" {
scope = "user"
}
if !validScopes[scope] {
return tools.Result{Content: fmt.Sprintf("memory_write: scope %q 必须是 user 或 project", scope), IsError: true}, nil
}
typ := strings.TrimSpace(a.Type)
if !validTypes[typ] {
return tools.Result{Content: fmt.Sprintf("memory_write: type %q 必须是 fact|preference|decision|episode|procedure 之一", typ), IsError: true}, nil
}
content := strings.TrimSpace(a.Content)
if content == "" {
return tools.Result{Content: "memory_write: content 必填且非空", IsError: true}, nil
}
if len([]rune(content)) > maxWriteContent {
return tools.Result{Content: fmt.Sprintf("memory_write: content 超过 %d 字符上限", maxWriteContent), IsError: true}, nil
}
var expires *time.Time
if a.ExpiresInDays > 0 {
t := time.Now().Add(time.Duration(a.ExpiresInDays*24) * time.Hour)
expires = &t
}
if err := t.store.Append(ctx, Entry{
Scope: scope, Type: typ, Content: content,
Source: "agent", CreatedAt: time.Now(), ExpiresAt: expires,
}); err != nil {
return tools.Result{Content: "memory_write: " + err.Error(), IsError: true}, nil
}
return tools.Result{Content: fmt.Sprintf("已记住(scope=%s type=%s)", scope, typ)}, nil
}