Skip to content

Commit 9587832

Browse files
committed
Sessions: semantic session_search over shared embedding backend
Phase 2: route the session VectorIndex through internal/embedding so session_search gains real semantic matching when an HTTP embeddings backend (Ollama/OpenAI/etc.) is configured, instead of being hardwired to go-vector RandomProjections. - VectorIndex.emb is now embedding.TextEmbedder, selected by an embedding.Config. Default (nil) stays RandomProjections — unchanged for existing users. - Add a vectors_meta.json fingerprint file next to vectors.gob. On init the persisted vectors are only reused when the embedder fingerprint (provider/model/dims) matches; switching backends forces a one-time rebuild in the new space. A missing meta (legacy layout) also rebuilds, since the old raw-text RP vectors live in a different space than the shared featurized embedder. - Rebuild batch-embeds the whole corpus via EmbedAll (one HTTP call) and adopts the episode index's 30s failure cool-down so a down backend is not hammered on every search or session save. - Resilience: Add never fails a session save and Search never surfaces an error when the backend is unavailable — both degrade silently to the keyword fallback in session_search_tool.go (left untouched). Wiring: Store.InitVectorIndex takes an *embedding.Config; the continue and telegram entry points pass memory's embedding config so a single endpoint powers both subsystems (a dedicated sessions block lands in Phase 4). Tests mirror memory's: HTTP semantic match (kitten→feline), fingerprint invalidation forcing a rebuild, and the rebuild backoff under a down backend.
1 parent 9d60500 commit 9587832

5 files changed

Lines changed: 390 additions & 95 deletions

File tree

cmd/odek/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1640,8 +1640,6 @@ func continueCmd(args []string) error {
16401640
if err != nil {
16411641
return fmt.Errorf("session store: %w", err)
16421642
}
1643-
// Initialize semantic search index (non-fatal on failure).
1644-
_ = store.InitVectorIndex()
16451643

16461644
var sess *session.Session
16471645
if sessionID != "" {
@@ -1659,6 +1657,10 @@ func continueCmd(args []string) error {
16591657
// Resolve config (no CLI flags for continue — uses session's model)
16601658
resolved := config.LoadConfig(config.CLIFlags{Model: sess.Model})
16611659

1660+
// Initialize semantic search index (non-fatal on failure). Sessions share
1661+
// memory's embedding backend so one endpoint config powers both.
1662+
_ = store.InitVectorIndex(resolved.Memory.Embedding)
1663+
16621664
// Auto-apply sandbox if session was sandboxed (even if config changed)
16631665
if sess.Sandbox && !resolved.Sandbox {
16641666
resolved.Sandbox = true

cmd/odek/telegram.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,9 @@ func telegramCmd(args []string) error {
143143
return err
144144
}
145145

146-
// Initialize semantic search index.
147-
if err := store.InitVectorIndex(); err != nil {
146+
// Initialize semantic search index. Sessions share memory's embedding
147+
// backend so a single Ollama/OpenAI endpoint config powers both.
148+
if err := store.InitVectorIndex(resolved.Memory.Embedding); err != nil {
148149
fmt.Fprintf(os.Stderr, "odek telegram: vector index: %v\n", err)
149150
// Non-fatal — search falls back to metadata-only.
150151
}

internal/session/session.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"sync"
2727
"time"
2828

29+
"github.com/BackendStack21/odek/internal/embedding"
2930
"github.com/BackendStack21/odek/internal/llm"
3031
"github.com/BackendStack21/odek/internal/redact"
3132
)
@@ -74,15 +75,16 @@ func NewStore() (*Store, error) {
7475
return &Store{dir: dir}, nil
7576
}
7677

77-
// InitVectorIndex initializes the semantic search index. Must be called
78+
// InitVectorIndex initializes the semantic search index using the embedding
79+
// backend selected by cfg (nil = default RandomProjections). Must be called
7880
// after NewStore, before the first Save. Safe to call multiple times —
79-
// subsequent calls are no-ops.
80-
func (s *Store) InitVectorIndex() error {
81+
// subsequent calls are no-ops once the index is ready.
82+
func (s *Store) InitVectorIndex(cfg *embedding.Config) error {
8183
if s.Vec != nil && s.Vec.Ready() {
8284
return nil // already initialized
8385
}
8486
s.Vec = new(VectorIndex)
85-
return s.Vec.Init(s.dir)
87+
return s.Vec.InitWithConfig(s.dir, cfg)
8688
}
8789

8890
// ── ID Generation ──────────────────────────────────────────────────────

0 commit comments

Comments
 (0)