feat: add workspace-isolated toolhost runtime and capability-gap skill loop

This commit is contained in:
2026-02-28 17:48:33 +08:00
parent ce9346e350
commit 7d6cf6b435
28 changed files with 2223 additions and 143 deletions

View File

@@ -0,0 +1,64 @@
package memory
import (
"path/filepath"
"testing"
"time"
)
func TestCapabilityGapStoreAndLoad(t *testing.T) {
dbPath := filepath.Join(t.TempDir(), "test.db")
store, err := NewSQLiteStore(dbPath, nil)
if err != nil {
t.Fatalf("NewSQLiteStore error: %v", err)
}
defer store.Close()
if err := store.SaveCapabilityGap("c1", "u1", "intent-a", "reason-a"); err != nil {
t.Fatalf("SaveCapabilityGap error: %v", err)
}
if err := store.SaveCapabilityGap("c1", "u1", "intent-b", "reason-b"); err != nil {
t.Fatalf("SaveCapabilityGap error: %v", err)
}
items, err := store.TopCapabilityGaps(10)
if err != nil {
t.Fatalf("TopCapabilityGaps error: %v", err)
}
if len(items) != 2 {
t.Fatalf("expected 2 items, got %d", len(items))
}
if items[0].Intent != "intent-b" {
t.Fatalf("expected newest first, got first intent=%s", items[0].Intent)
}
}
func TestTopCapabilityGapClusters(t *testing.T) {
dbPath := filepath.Join(t.TempDir(), "cluster.db")
store, err := NewSQLiteStore(dbPath, nil)
if err != nil {
t.Fatalf("NewSQLiteStore error: %v", err)
}
defer store.Close()
if err := store.SaveCapabilityGap("c1", "u1", "帮我查询 data 目录", "no_skill_matched"); err != nil {
t.Fatalf("SaveCapabilityGap error: %v", err)
}
if err := store.SaveCapabilityGap("c1", "u2", "帮我 查询 data 目录", "no_skill_matched"); err != nil {
t.Fatalf("SaveCapabilityGap error: %v", err)
}
if err := store.SaveCapabilityGap("c2", "u3", "读取配置文件内容", "tool_call_failed:file"); err != nil {
t.Fatalf("SaveCapabilityGap error: %v", err)
}
clusters, err := store.TopCapabilityGapClusters(10, time.Now().UTC().Add(-1*time.Hour))
if err != nil {
t.Fatalf("TopCapabilityGapClusters error: %v", err)
}
if len(clusters) == 0 {
t.Fatalf("expected non-empty clusters")
}
if clusters[0].Count < 2 {
t.Fatalf("expected first cluster count >= 2, got %d", clusters[0].Count)
}
}