Files
HomeAgent/internal/sdk/selftest.go
root 9d5a914941 Phase 0.1/1/3/6: 核心生产问题修复
Healthcheck 隔离 (Phase 0.1):
- 新增 internal/sdk/selftest.go: VirtualInstance 完全隔离自检空间
- PluginSDK.Selftest()/SelftestReset() 暴露隔离实例 (含 mutex)
- LLM 自检只读白名单 isSafeReadonlyTool 防写类工具污染生产
- 单测验证: healthcheck 后生产实例内容不变 + 无残留
- 存量清理: 删除 gotest/luatest 残留目录

GraphDB 去重 (Phase 1):
- migrateRelationUnique: 启动自动重建 relations 表加 UNIQUE 约束并去重
- Commit 改为存在性检查, 重复三元组仅刷新 confidence 不重复插入
- 3 个 dedup 单测全绿

配置时长解析 (Phase 3):
- parseDurationExtended 支持 2d/1w/3h 等人类可读单位
- GetDuration 全局生效, 防 2d 静默回退 30m

Agentcli 通知风暴治理 (Phase 6):
- 语义通知: 累积 notify_bytes(2KB) 或间隔 notify_interval(2s) 触发
- 生命周期即时通知: 启动/进程退出/EOF 立即通知
- 可配置 settings, 保留通知机制保证 agent 感知终端存在
- 运维止血: 已杀掉幽灵 PID 3716282 (bash git sparse clone 运行 16h)

Plan.md: 新增设计意图备忘(插件即App/分层记忆), 更新各 Phase 进度
2026-08-12 13:51:40 +08:00

108 lines
3.0 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 sdk
import (
"fmt"
"os"
"path/filepath"
"sync"
"gitcode.com/JianFeeeee/HomeAgent/internal/knowledge"
"gitcode.com/JianFeeeee/HomeAgent/internal/memory"
doc "gitcode.com/JianFeeeee/HomeAgent/internal/memory/document"
"gitcode.com/JianFeeeee/HomeAgent/internal/memory/text"
)
// VirtualInstance 是完全隔离的虚拟存储集合,供内置插件(如 healthcheck
// 做不污染生产存储的"写→查→删"往返自检。所有写入发生在独立临时目录,
// 由 Cleanup 统一销毁。
type VirtualInstance struct {
Memory MemoryAPI
Knowledge KnowledgeAPI
DocMemory DocMemoryAPI
TextMemory TextMemoryAPI
dir string
mu sync.Mutex
created bool
}
// newBaseDir 返回一个隔离的临时根目录hot 前缀,避免与生产数据混淆)。
func newBaseDir(scope string) (string, error) {
return os.MkdirTemp("", "homeagent_selftest_"+scope+"_")
}
// NewVirtualInstance 创建完全隔离的测试实例,使用独立临时目录。
func NewVirtualInstance(scope string) (*VirtualInstance, error) {
if scope == "" {
scope = "hc"
}
base, err := newBaseDir(scope)
if err != nil {
return nil, err
}
v := &VirtualInstance{dir: base, created: true}
if err := v.initLocked(); err != nil {
os.RemoveAll(base)
return nil, err
}
return v, nil
}
// initLocked 初始化各隔离存储。调用方须持 v.mu。
func (v *VirtualInstance) initLocked() error {
memDB, err := memory.NewGraphDB(filepath.Join(v.dir, "graph.db"))
if err != nil {
return fmt.Errorf("virtual graph db: %w", err)
}
v.Memory = NewGraphMemory(memDB)
ks := knowledge.NewStore(filepath.Join(v.dir, "knowledge"))
if err := ks.Start(); err != nil {
return fmt.Errorf("virtual knowledge store: %w", err)
}
v.Knowledge = NewKnowledge(ks)
ds := doc.NewStore(filepath.Join(v.dir, "documents"))
if err := ds.Start(); err != nil {
return fmt.Errorf("virtual doc store: %w", err)
}
v.DocMemory = NewDocMemory(ds)
tm := text.New(filepath.Join(v.dir, "text"))
if err := tm.Start(); err != nil {
return fmt.Errorf("virtual text memory: %w", err)
}
v.TextMemory = NewTextMemory(tm)
return nil
}
// Cleanup 关闭并销毁该虚拟实例的全部临时存储。之后实例不可再用。
func (v *VirtualInstance) Cleanup() {
v.mu.Lock()
defer v.mu.Unlock()
if !v.created {
return
}
if tm, ok := v.TextMemory.(*textMemoryImpl); ok && tm.tm != nil {
tm.tm.Stop()
}
if ds, ok := v.DocMemory.(*docMemoryImpl); ok && ds.ds != nil {
ds.ds.Stop()
}
if ks, ok := v.Knowledge.(*knowledgeImpl); ok && ks.ks != nil {
ks.ks.Stop()
}
if gm, ok := v.Memory.(*graphMemory); ok && gm.db != nil {
gm.db.Close()
}
os.RemoveAll(v.dir)
v.created = false
}
// Reset 清理当前实例并重建一个全新的隔离实例,用于每轮自检前重置状态。
// 返回新实例;失败时旧实例已被清理、返回 err调用方需重新创建。
func (v *VirtualInstance) Reset(scope string) (*VirtualInstance, error) {
v.Cleanup()
return NewVirtualInstance(scope)
}