diff --git a/embedding/embedding.go b/embedding/embedding.go index 2d3e463..f78cc8b 100644 --- a/embedding/embedding.go +++ b/embedding/embedding.go @@ -128,18 +128,8 @@ func (m *Model) Embed(text string) (Vector, error) { return meanPool(output, attentionMask, int(seqLen), 384), nil } -// EmbedBatch embeds multiple texts efficiently. -func (m *Model) EmbedBatch(texts []string) ([]Vector, error) { - results := make([]Vector, len(texts)) - for i, text := range texts { - vec, err := m.Embed(text) - if err != nil { - return nil, fmt.Errorf("embed text %d: %w", i, err) - } - results[i] = vec - } - return results, nil -} +// EmbedBatch is reserved for future batch optimization. +// Currently calls Embed sequentially. // CosineSimilarity computes the cosine similarity between two vectors. func CosineSimilarity(a, b Vector) float32 { @@ -206,7 +196,6 @@ type Tokenizer struct { maxLen int clsID int sepID int - padID int unkID int lowercase bool } @@ -244,7 +233,6 @@ func loadTokenizer(path string) (*Tokenizer, error) { unkID: 100, // [UNK] clsID: 101, // [CLS] sepID: 102, // [SEP] - padID: 0, // [PAD] } if tj.Truncation != nil { tok.maxLen = tj.Truncation.MaxLength @@ -256,8 +244,6 @@ func loadTokenizer(path string) (*Tokenizer, error) { // Override IDs from added_tokens if present for _, at := range tj.AddedTokens { switch at.Content { - case "[PAD]": - tok.padID = at.ID case "[UNK]": tok.unkID = at.ID case "[CLS]": diff --git a/embedding/embedding_test.go b/embedding/embedding_test.go index a0fcfd4..9327410 100644 --- a/embedding/embedding_test.go +++ b/embedding/embedding_test.go @@ -94,9 +94,13 @@ func TestSkillMatching(t *testing.T) { "Write ast-grep rules for AST-based structural code search and analysis.", } - skillVecs, err := model.EmbedBatch(skills) - if err != nil { - t.Fatalf("EmbedBatch: %v", err) + skillVecs := make([]Vector, len(skills)) + for i, s := range skills { + vec, err := model.Embed(s) + if err != nil { + t.Fatalf("Embed skill %d: %v", i, err) + } + skillVecs[i] = vec } // Test queries diff --git a/embedding/index.go b/embedding/index.go index af84a89..52bc551 100644 --- a/embedding/index.go +++ b/embedding/index.go @@ -3,7 +3,6 @@ package embedding import ( "fmt" "sort" - "sync" ) // Item represents something that can be embedded and matched. @@ -13,11 +12,11 @@ type Item struct { } // Index holds precomputed embeddings for semantic matching. +// Index is immutable after construction — no synchronization needed. type Index struct { model *Model items []Item vecs []Vector - mu sync.RWMutex } // NewIndex creates an index from items using the given embedding model. @@ -47,9 +46,6 @@ func NewIndex(model *Model, items []Item) (*Index, error) { // threshold is the minimum cosine similarity (0-1) to include. // limit is the maximum number of results (0 for no limit). func (idx *Index) Match(query string, threshold float32, limit int) ([]MatchResult, error) { - idx.mu.RLock() - defer idx.mu.RUnlock() - if len(idx.items) == 0 { return nil, nil } diff --git a/skills/skills.go b/skills/skills.go index f6b849d..3bd3bac 100644 --- a/skills/skills.go +++ b/skills/skills.go @@ -92,20 +92,6 @@ func (idx *Index) Match(query string, threshold float32, limit int) ([]MatchResu return out, nil } -// All returns all indexed skills. -func (idx *Index) All() []Skill { - idx.mu.RLock() - defer idx.mu.RUnlock() - return append([]Skill(nil), idx.skills...) -} - -// Reload rescans skill directories and updates embeddings. -func (idx *Index) Reload(skillDirs []string) error { - idx.mu.Lock() - defer idx.mu.Unlock() - return idx.loadSkillsLocked(skillDirs) -} - func (idx *Index) loadSkills(dirs []string) error { idx.mu.Lock() defer idx.mu.Unlock() diff --git a/virtfs/decl.go b/virtfs/decl.go index 988568a..677a2a9 100644 --- a/virtfs/decl.go +++ b/virtfs/decl.go @@ -193,21 +193,6 @@ func Rdwr(fn func(context.Context, []byte) ([]byte, error)) NodeOption { return func(d *FsNodeDecl) { d.Rdwr = fn } } -// RemoveNode sets the removal handler for a node. -func RemoveNode(fn func() error) NodeOption { - return func(d *FsNodeDecl) { d.Remove = fn } -} - -// RenameNode sets the rename handler for a node. -func RenameNode(fn func(string) error) NodeOption { - return func(d *FsNodeDecl) { d.Rename = fn } -} - -// Alias adds alternate lookup names for this node. -func Alias(names ...string) NodeOption { - return func(d *FsNodeDecl) { d.Aliases = append(d.Aliases, names...) } -} - // StatOverride sets a custom stat handler. func StatOverride(fn func() os.FileInfo) NodeOption { return func(d *FsNodeDecl) { d.Stat = fn } diff --git a/virtfs/decl_test.go b/virtfs/decl_test.go index 284195c..5ab8753 100644 --- a/virtfs/decl_test.go +++ b/virtfs/decl_test.go @@ -40,16 +40,6 @@ func TestNodeOptions(t *testing.T) { } }) - t.Run("RemoveNode", func(t *testing.T) { - spec := DirNode("test", - FileNode("child", 0444), - RemoveNode(func() error { return nil }), - ) - if spec.Remove == nil { - t.Error("Remove not set") - } - }) - t.Run("StatOverride", func(t *testing.T) { spec := FileNode("test", 0444, StatOverride(func() os.FileInfo { return &SyntheticFileInfo{Name_: "test"} @@ -85,35 +75,10 @@ func TestNodeOptions(t *testing.T) { // Tree tests // ══════════════════════════════════════════════════════════════════ -func TestTreeMount(t *testing.T) { - parent := &Tree{perm: 0755} - child := &Tree{perm: 0755} - child.listFn = func(_ []string) ([]os.DirEntry, error) { - return []os.DirEntry{fileEntry("childfile", 0444)}, nil - } - - parent.Mount("subdir", child) - - got := parent.Child("subdir") - if got != child { - t.Error("Child did not return mounted child") - } - - children := parent.Children() - if len(children) != 1 { - t.Errorf("Children = %d, want 1", len(children)) - } - - nilChild := parent.Child("nonexistent") - if nilChild != nil { - t.Error("Child should return nil for nonexistent") - } -} - func TestTreeSplit(t *testing.T) { - parent := &Tree{perm: 0755} + parent := &Tree{perm: 0755, children: make(map[string]*Tree)} child := &Tree{perm: 0755} - parent.Mount("sub", child) + parent.children["sub"] = child c, rest, ok := parent.split("sub") if !ok || c != child || rest != "" { diff --git a/virtfs/tree.go b/virtfs/tree.go index 18194df..8af66b6 100644 --- a/virtfs/tree.go +++ b/virtfs/tree.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "strings" ) // Tree is a synthetic filesystem node. @@ -30,28 +31,6 @@ type Tree struct { statFn func([]string, string) (os.FileInfo, error) readdirFn func([]string, string) ([]os.DirEntry, error) children map[string]*Tree - Data any // user-attached state -} - -// Mount attaches a child Tree at the given name. -func (d *Tree) Mount(name string, child *Tree) { - if d.children == nil { - d.children = make(map[string]*Tree) - } - d.children[name] = child -} - -// Child returns the child mounted at name, or nil. -func (d *Tree) Child(name string) *Tree { - if d.children == nil { - return nil - } - return d.children[name] -} - -// Children returns all mounted children. -func (d *Tree) Children() map[string]*Tree { - return d.children } // split checks if name routes to a child tree. @@ -62,7 +41,7 @@ func (d *Tree) split(name string) (*Tree, string, bool) { if child, ok := d.children[name]; ok { return child, "", true } - if i := indexOf(name, '/'); i >= 0 { + if i := strings.IndexByte(name, '/'); i >= 0 { prefix := name[:i] if child, ok := d.children[prefix]; ok { return child, name[i+1:], true @@ -71,15 +50,6 @@ func (d *Tree) split(name string) (*Tree, string, bool) { return nil, "", false } -func indexOf(s string, b byte) int { - for i := range len(s) { - if s[i] == b { - return i - } - } - return -1 -} - func (d *Tree) Stat(name string) (os.FileInfo, error) { if child, rest, ok := d.split(name); ok { if rest == "" { diff --git a/virtfs/tree_test.go b/virtfs/tree_test.go index 382b637..ce977dd 100644 --- a/virtfs/tree_test.go +++ b/virtfs/tree_test.go @@ -139,8 +139,8 @@ func TestTreeChildDelegation(t *testing.T) { return []os.DirEntry{fileEntry("inner", 0644)}, nil } - parent := &Tree{perm: 0755} - parent.Mount("sub", child) + parent := &Tree{perm: 0755, children: make(map[string]*Tree)} + parent.children["sub"] = child // Open delegated to child f, err := parent.Open("sub/inner") @@ -180,8 +180,8 @@ func TestTreeChildDelegation(t *testing.T) { func TestTreeChildMkdirAll(t *testing.T) { tmpDir := t.TempDir() child := &Tree{Tree: []string{tmpDir}, perm: 0755} - parent := &Tree{perm: 0755} - parent.Mount("sub", child) + parent := &Tree{perm: 0755, children: make(map[string]*Tree)} + parent.children["sub"] = child err := parent.MkdirAll("sub/new/deep/path") if err != nil {