develop
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
cb584a2ac8 |
feat(d5d6): real memory database — vec0 statically linked, hard-fail boot, stats tool
Closes D-5 / D-6 (sqlite-vec dylib bundling) carry-forwards from the 2026-05-04 audit by adopting jkrukowski/SQLiteVec as a SPM dependency. The package's CSQLiteVec target compiles sqlite3.c + sqlite-vec.c into one statically-linked C target with `core_vec_init()` registering vec0 as an auto-extension. All sqlite3_* calls in Replay's SQLiteConnection and Memory's MemoryStore resolve to this bundled SQLite (vec0 always available) instead of Apple's stripped /usr/lib/libsqlite3.dylib. The retired hand-rolled approach (dlsym pathway + JARVIS_VEC0_STUB_PATH env-flag + Bundle.module placeholder text file) never worked on macOS because Apple stripped sqlite3_load_extension from the system libsqlite3. Memory init has been silently dormant since Phase 7 (2026-04 onward), which is what made B-02 (history threading) appear permanently broken to the user during dogfooding even after the |
||
|
|
707c45b355 |
feat(track-d 2): register SearchMemoryTool + ForgetFactTool with MCP runtime
Closes the audit's "tools exist but unregistered" finding from
.planning/audit-2026-05-03/memory-audit.md §4-5: SearchMemoryTool +
ForgetFactTool source files have lived in `packages/MCP/Sources/MCP/
InProcess/` since Plan 07-03 with zero non-test instantiation. The agent
loop has had no way to call into memory.
Wiring:
- New `App/MCP/InProcessMemoryAdapters.swift` bridges MCP's tool
dispatch protocols to Memory's actors:
* `HybridSearchAdapter: HybridSearchDispatching` wraps
`Memory.HybridSearch` and translates `[FactRef]` → `[SearchMemoryHit]`
(so MCP doesn't need to import Memory).
* `ForgetFactStoreAdapter: ForgetFactDispatching` wraps
`MemoryStore.forgetFact`.
- `installMemory` builds an `InProcessToolRegistry` and registers tools
based on preconditions:
* `forget_fact` registers when `memoryStore != nil` (writes need DB)
* `search_memory` registers when `memorySearchAvailable && embedder
init succeeds` (reads need DB + vec0 + Ollama loopback)
- Embedder construction (`OllamaEmbeddingClient` loopback assertion)
failure is caught + logged; degrades to "writes ok, no search"
rather than failing the whole subsystem.
- New `inProcessToolRegistry: InProcessToolRegistry?` ivar, exposed
@testable.
Test seam: `AppDelegate.buildInProcessToolRegistry(forgetDispatcher:
searchDispatcher:)` is the pure registry-construction helper — takes
already-built dispatchers (or nil) and applies the gating rules. Tests
inject stub dispatchers to assert positive registration without needing
a real `MemoryStore` (which requires vec0.dylib, env-gated in CI).
Tests added (compile-time gates per
.planning/debug/xctest-launch-runningboard-error-5.md):
- `test_D2_noToolsRegisteredWhenStoreUnavailable` — production reality
on every cold launch (vec0 placeholder)
- `test_D2_bothToolsRegisterWhenBothDispatchersPresent` — store + search
available
- `test_D2_onlyForgetRegistersWhenSearchUnavailable` — store ok, vec
failed (the future state once custom libsqlite3 lands but vec0.dylib
is missing)
- `test_D2_emptyRegistryWhenBothDispatchersNil` — degenerate case
Out of scope: exposing the registered tools to the LLM via
`AgentOrchestrator.availableTools` (currently `[]` — separate audit gap,
affects helper tools too). The "tools exist but unregistered" gap is
closed; the "tools exposed to LLM" gap is independent.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|