Repository navigation
Wire the agent's embedding service by construction instead of re-injecting it per engine swap - #1335
Conversation
…loses #1328) GraphToolExecutor previously captured a snapshot of the embedding service at construction. The service loads in a background task after daemon startup, so an executor built before embeddings finished was stuck with `None` until the next engine swap — disabling search_semantic and skill-based select_tools routing (the full tool list was always sent). Two construction sites had to remember to re-pass the service; one passed `None`. Make the executor hold the shared `Arc<RwLock<Option<Arc<NodeEmbeddingService>>>>` handle (new `SharedEmbeddingService` alias, expressible in the agent crate with no daemon dependency) and read it per call. The executor now always sees the current value, so a turn run after embeddings load uses semantic search and skill routing with no engine swap, and no construction site can wire a stale or `None` service. - agent/tools.rs: field type → shared handle; read live in exec_search_semantic, exec_search_skills, select_tools, and the embedding_service() accessor (now async). Deleted the unused new / new_with_optional_services constructors. Added a test asserting the executor holds the shared handle (Arc::ptr_eq), not a snapshot. - daemon/local_agent_service.rs: build_noop_service and replace_engine pass the shared handle directly; dropped the snapshot read. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code Review — PR #1335 (issue #1328)Review Type: Initial review · Rust-only change (2 files) · race-condition fix for embedding-service wiring Requirements Check
Verification performed
Findings🟢 Locking is correct — no guard held across
|
malibio
left a comment
There was a problem hiding this comment.
Reviewed via /pragmatic-code-review — APPROVE. Race fix is correct, locking is sound (no guard held across await), dead constructors fully removed, new test pins the shared-handle invariant. Full findings posted as a PR comment.
…loses #1328) (#1335) GraphToolExecutor previously captured a snapshot of the embedding service at construction. The service loads in a background task after daemon startup, so an executor built before embeddings finished was stuck with `None` until the next engine swap — disabling search_semantic and skill-based select_tools routing (the full tool list was always sent). Two construction sites had to remember to re-pass the service; one passed `None`. Make the executor hold the shared `Arc<RwLock<Option<Arc<NodeEmbeddingService>>>>` handle (new `SharedEmbeddingService` alias, expressible in the agent crate with no daemon dependency) and read it per call. The executor now always sees the current value, so a turn run after embeddings load uses semantic search and skill routing with no engine swap, and no construction site can wire a stale or `None` service. - agent/tools.rs: field type → shared handle; read live in exec_search_semantic, exec_search_skills, select_tools, and the embedding_service() accessor (now async). Deleted the unused new / new_with_optional_services constructors. Added a test asserting the executor holds the shared handle (Arc::ptr_eq), not a snapshot. - daemon/local_agent_service.rs: build_noop_service and replace_engine pass the shared handle directly; dropped the snapshot read. Co-authored-by: Michael Libio <malibio@Michaels-Mac-mini.local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Closes #1328