spatial-memory-mcp 1.6.2__tar.gz → 1.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of spatial-memory-mcp might be problematic. Click here for more details.
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/.gitignore +1 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/CHANGELOG.md +27 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/PKG-INFO +1 -1
- spatial_memory_mcp-1.7.0/docs/CONFIGURATION.md +245 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/pyproject.toml +1 -1
- spatial_memory_mcp-1.7.0/scripts/test_auto_decay.py +288 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/__init__.py +1 -1
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/adapters/lancedb_repository.py +2 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/config.py +37 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/models.py +31 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/response_types.py +4 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/factory.py +37 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/server.py +100 -32
- spatial_memory_mcp-1.7.0/spatial_memory/services/decay_manager.py +406 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/services/utility.py +12 -0
- spatial_memory_mcp-1.7.0/tests/integration/test_auto_decay.py +435 -0
- spatial_memory_mcp-1.7.0/tests/unit/test_decay_manager.py +584 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/.env.example +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/CLAUDE.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/CONTRIBUTING.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/ISSUES-TRACKER.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/LICENSE +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/LIFECYCLE_PHASE_PLAN.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/MARKETING.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/PHASE4B_PLAN.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/PHASE4_PLAN.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/PHASE5_UTILITIES_PLAN.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/README.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/SECURITY.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/SPATIAL-MEMORY-ARCHITECTURE-DIAGRAMS.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/SPATIAL-MEMORY-MCP-SERVER-PLAN (1).md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/docs/API.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/docs/BENCHMARKS.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/docs/MCP_SERVER_INSTRUCTIONS.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/docs/METRICS.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/docs/TECHNICAL_HIGHLIGHTS.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/docs/troubleshooting.md +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/examples/demo_config_logging.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/scripts/benchmark.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/scripts/inspect_db.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/scripts/populate_test_data.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/scripts/test_all_tools.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/__main__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/adapters/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/cache.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/circuit_breaker.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/connection_pool.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/consolidation_strategies.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/database.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/db_idempotency.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/db_indexes.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/db_migrations.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/db_search.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/db_versioning.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/embeddings.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/errors.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/file_security.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/filesystem.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/health.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/helpers.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/import_security.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/lifecycle_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/logging.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/metrics.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/rate_limiter.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/security.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/spatial_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/tracing.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/utils.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/core/validation.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/migrations/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/ports/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/ports/repositories.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/py.typed +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/services/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/services/export_import.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/services/lifecycle.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/services/memory.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/services/spatial.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/tools/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/tools/definitions.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/verify.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/hdbscan/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/lancedb/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/lancedb/index.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/lancedb/rerankers.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/lancedb/table.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/mcp/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/mcp/server/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/mcp/server/stdio.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/mcp/types.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/openai/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/pyarrow/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/pyarrow/parquet.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/sklearn/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/sklearn/metrics/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/stubs/umap/__init__.pyi +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/conftest.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/conftest.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_backup_restore.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_concurrent_writes.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_cross_process_locking.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_database.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_database_safeguards.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_embeddings.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_enterprise_features.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_indexing.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_mcp_server.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_namespace_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_phase5_tools.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_security_edge_cases.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_server_v153.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/integration/test_ttl_snapshots.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_config.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_connection_pool.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_health.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_helpers.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_logging.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_metrics.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_models.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_rate_limiter.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/test_validation.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/__init__.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_cache.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_circuit_breaker.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_config_phase5.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_errors_phase5.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_export_import_service.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_export_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_file_security.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_filesystem.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_hybrid_search_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_import_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_import_security.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_lancedb_repository_phase5.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_lifecycle_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_lifecycle_service.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_memory_service.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_models_phase5.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_process_lock.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_security_facade.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_spatial_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_spatial_service.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_stats_ops.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_tracing.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_utility_service.py +0 -0
- {spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/tests/unit/test_utils.py +0 -0
|
@@ -11,6 +11,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
- Medium severity architectural improvements (MED-ARCH-001 through MED-ARCH-004)
|
|
12
12
|
- Migration system (MED-DB-005)
|
|
13
13
|
|
|
14
|
+
## [1.7.0] - 2026-02-02
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- **Auto-Decay Feature**: Automatic time-based importance decay during recall operations
|
|
18
|
+
- Memories automatically lose importance over time if not accessed (exponential decay)
|
|
19
|
+
- `effective_importance` field added to `recall` and `hybrid_recall` responses
|
|
20
|
+
- Results re-ranked by `similarity × effective_importance` to favor recent memories
|
|
21
|
+
- Background persistence thread batches and saves decay updates to database
|
|
22
|
+
- Configurable via environment variables:
|
|
23
|
+
- `SPATIAL_MEMORY_AUTO_DECAY_ENABLED` (default: true)
|
|
24
|
+
- `SPATIAL_MEMORY_AUTO_DECAY_PERSIST_ENABLED` (default: true)
|
|
25
|
+
- `SPATIAL_MEMORY_AUTO_DECAY_PERSIST_BATCH_SIZE` (default: 100)
|
|
26
|
+
- `SPATIAL_MEMORY_AUTO_DECAY_PERSIST_FLUSH_INTERVAL_SECONDS` (default: 5.0)
|
|
27
|
+
- `SPATIAL_MEMORY_AUTO_DECAY_MIN_CHANGE_THRESHOLD` (default: 0.01)
|
|
28
|
+
- `SPATIAL_MEMORY_AUTO_DECAY_MAX_QUEUE_SIZE` (default: 10000)
|
|
29
|
+
- Access count slows decay: frequently accessed memories stay relevant longer
|
|
30
|
+
- Minimum importance floor prevents memories from decaying to zero
|
|
31
|
+
- Configuration documentation (`docs/CONFIGURATION.md`)
|
|
32
|
+
- Complete reference for all environment variables
|
|
33
|
+
- Examples for `.mcp.json`, Claude Desktop, and `.env` files
|
|
34
|
+
- Auto-decay configuration guide
|
|
35
|
+
- Test script for verifying auto-decay (`scripts/test_auto_decay.py`)
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- `MemoryResultDict` and `HybridMemoryDict` response types now include optional `effective_importance` field
|
|
39
|
+
- `MemoryResult` and `HybridMemoryMatch` models now include `last_accessed` and `access_count` fields
|
|
40
|
+
|
|
14
41
|
## [1.6.2] - 2026-02-02
|
|
15
42
|
|
|
16
43
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: spatial-memory-mcp
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
4
4
|
Summary: Spatial bidirectional persistent memory MCP server for LLMs - vector-based semantic memory as a navigable landscape
|
|
5
5
|
Project-URL: Homepage, https://github.com/arman-tech/spatial-memory-mcp
|
|
6
6
|
Project-URL: Repository, https://github.com/arman-tech/spatial-memory-mcp
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Configuration Guide
|
|
2
|
+
|
|
3
|
+
Spatial Memory MCP Server is configured via environment variables with the `SPATIAL_MEMORY_` prefix.
|
|
4
|
+
|
|
5
|
+
## Configuration Methods
|
|
6
|
+
|
|
7
|
+
### 1. `.mcp.json` (Recommended for MCP Clients)
|
|
8
|
+
|
|
9
|
+
Create a `.mcp.json` file in your project root:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"spatial-memory": {
|
|
15
|
+
"command": "spatial-memory",
|
|
16
|
+
"env": {
|
|
17
|
+
"SPATIAL_MEMORY_AUTO_DECAY_ENABLED": "true",
|
|
18
|
+
"SPATIAL_MEMORY_AUTO_DECAY_PERSIST_ENABLED": "false",
|
|
19
|
+
"SPATIAL_MEMORY_LOG_LEVEL": "INFO"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 2. Claude Desktop Configuration
|
|
27
|
+
|
|
28
|
+
Edit `claude_desktop_config.json`:
|
|
29
|
+
|
|
30
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
31
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"spatial-memory": {
|
|
37
|
+
"command": "spatial-memory",
|
|
38
|
+
"env": {
|
|
39
|
+
"SPATIAL_MEMORY_MEMORY_PATH": "/path/to/storage",
|
|
40
|
+
"SPATIAL_MEMORY_AUTO_DECAY_ENABLED": "true"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Environment Variables
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# Export before running
|
|
51
|
+
export SPATIAL_MEMORY_AUTO_DECAY_ENABLED=true
|
|
52
|
+
export SPATIAL_MEMORY_LOG_LEVEL=DEBUG
|
|
53
|
+
spatial-memory
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Or inline:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
SPATIAL_MEMORY_AUTO_DECAY_ENABLED=false spatial-memory
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 4. `.env` File
|
|
63
|
+
|
|
64
|
+
Create a `.env` file in your working directory:
|
|
65
|
+
|
|
66
|
+
```env
|
|
67
|
+
SPATIAL_MEMORY_MEMORY_PATH=./.spatial-memory
|
|
68
|
+
SPATIAL_MEMORY_LOG_LEVEL=INFO
|
|
69
|
+
SPATIAL_MEMORY_AUTO_DECAY_ENABLED=true
|
|
70
|
+
SPATIAL_MEMORY_AUTO_DECAY_PERSIST_ENABLED=true
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## Configuration Reference
|
|
76
|
+
|
|
77
|
+
### Storage
|
|
78
|
+
|
|
79
|
+
| Variable | Default | Description |
|
|
80
|
+
|----------|---------|-------------|
|
|
81
|
+
| `SPATIAL_MEMORY_MEMORY_PATH` | `./.spatial-memory` | Path to LanceDB storage directory |
|
|
82
|
+
| `SPATIAL_MEMORY_ACKNOWLEDGE_NETWORK_FILESYSTEM_RISK` | `false` | Suppress network filesystem warnings |
|
|
83
|
+
|
|
84
|
+
### Embedding Model
|
|
85
|
+
|
|
86
|
+
| Variable | Default | Description |
|
|
87
|
+
|----------|---------|-------------|
|
|
88
|
+
| `SPATIAL_MEMORY_EMBEDDING_MODEL` | `all-MiniLM-L6-v2` | Model name or `openai:model-name` |
|
|
89
|
+
| `SPATIAL_MEMORY_EMBEDDING_DIMENSIONS` | `384` | Vector dimensions (auto-detected) |
|
|
90
|
+
| `SPATIAL_MEMORY_EMBEDDING_BACKEND` | `auto` | Backend: `auto`, `onnx`, or `pytorch` |
|
|
91
|
+
|
|
92
|
+
### OpenAI (Optional)
|
|
93
|
+
|
|
94
|
+
| Variable | Default | Description |
|
|
95
|
+
|----------|---------|-------------|
|
|
96
|
+
| `SPATIAL_MEMORY_OPENAI_API_KEY` | `null` | OpenAI API key for embeddings |
|
|
97
|
+
| `SPATIAL_MEMORY_OPENAI_EMBEDDING_MODEL` | `text-embedding-3-small` | OpenAI model to use |
|
|
98
|
+
|
|
99
|
+
### Server
|
|
100
|
+
|
|
101
|
+
| Variable | Default | Description |
|
|
102
|
+
|----------|---------|-------------|
|
|
103
|
+
| `SPATIAL_MEMORY_LOG_LEVEL` | `INFO` | Logging level: `DEBUG`, `INFO`, `WARNING`, `ERROR` |
|
|
104
|
+
| `SPATIAL_MEMORY_LOG_FORMAT` | `text` | Log format: `text` or `json` |
|
|
105
|
+
|
|
106
|
+
### Memory Defaults
|
|
107
|
+
|
|
108
|
+
| Variable | Default | Description |
|
|
109
|
+
|----------|---------|-------------|
|
|
110
|
+
| `SPATIAL_MEMORY_DEFAULT_NAMESPACE` | `default` | Default namespace for memories |
|
|
111
|
+
| `SPATIAL_MEMORY_DEFAULT_IMPORTANCE` | `0.5` | Default importance (0.0-1.0) |
|
|
112
|
+
|
|
113
|
+
### Limits
|
|
114
|
+
|
|
115
|
+
| Variable | Default | Description |
|
|
116
|
+
|----------|---------|-------------|
|
|
117
|
+
| `SPATIAL_MEMORY_MAX_BATCH_SIZE` | `100` | Max memories per batch operation |
|
|
118
|
+
| `SPATIAL_MEMORY_MAX_RECALL_LIMIT` | `100` | Max results from recall |
|
|
119
|
+
| `SPATIAL_MEMORY_MAX_JOURNEY_STEPS` | `20` | Max steps in journey |
|
|
120
|
+
| `SPATIAL_MEMORY_MAX_WANDER_STEPS` | `20` | Max steps in wander |
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Auto-Decay Settings
|
|
125
|
+
|
|
126
|
+
Auto-decay automatically reduces the importance of memories over time, favoring recently accessed memories in search results.
|
|
127
|
+
|
|
128
|
+
| Variable | Default | Description |
|
|
129
|
+
|----------|---------|-------------|
|
|
130
|
+
| `SPATIAL_MEMORY_AUTO_DECAY_ENABLED` | `true` | Enable decay calculation during recall |
|
|
131
|
+
| `SPATIAL_MEMORY_AUTO_DECAY_PERSIST_ENABLED` | `true` | Save decayed values to database |
|
|
132
|
+
| `SPATIAL_MEMORY_AUTO_DECAY_PERSIST_BATCH_SIZE` | `100` | Batch size for persistence |
|
|
133
|
+
| `SPATIAL_MEMORY_AUTO_DECAY_PERSIST_FLUSH_INTERVAL_SECONDS` | `5.0` | How often to flush updates (seconds) |
|
|
134
|
+
| `SPATIAL_MEMORY_AUTO_DECAY_MIN_CHANGE_THRESHOLD` | `0.01` | Min change to trigger persist (1%) |
|
|
135
|
+
| `SPATIAL_MEMORY_AUTO_DECAY_MAX_QUEUE_SIZE` | `10000` | Max queued updates |
|
|
136
|
+
|
|
137
|
+
### How Auto-Decay Works
|
|
138
|
+
|
|
139
|
+
1. **Exponential Decay**: `effective_importance = importance × 2^(-days_since_access / half_life)`
|
|
140
|
+
2. **Default Half-Life**: 30 days (memory loses 50% importance after 30 days without access)
|
|
141
|
+
3. **Access Count Bonus**: Frequently accessed memories decay slower
|
|
142
|
+
4. **Minimum Floor**: Importance never drops below 10%
|
|
143
|
+
|
|
144
|
+
### Example Configurations
|
|
145
|
+
|
|
146
|
+
**Disable auto-decay entirely:**
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"env": {
|
|
150
|
+
"SPATIAL_MEMORY_AUTO_DECAY_ENABLED": "false"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Enable decay calculation but don't persist changes:**
|
|
156
|
+
```json
|
|
157
|
+
{
|
|
158
|
+
"env": {
|
|
159
|
+
"SPATIAL_MEMORY_AUTO_DECAY_ENABLED": "true",
|
|
160
|
+
"SPATIAL_MEMORY_AUTO_DECAY_PERSIST_ENABLED": "false"
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Aggressive persistence (frequent flushes):**
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"env": {
|
|
169
|
+
"SPATIAL_MEMORY_AUTO_DECAY_PERSIST_FLUSH_INTERVAL_SECONDS": "1.0",
|
|
170
|
+
"SPATIAL_MEMORY_AUTO_DECAY_MIN_CHANGE_THRESHOLD": "0.001"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Full Example: `.mcp.json`
|
|
178
|
+
|
|
179
|
+
```json
|
|
180
|
+
{
|
|
181
|
+
"mcpServers": {
|
|
182
|
+
"spatial-memory": {
|
|
183
|
+
"command": "spatial-memory",
|
|
184
|
+
"env": {
|
|
185
|
+
"SPATIAL_MEMORY_MEMORY_PATH": "./my-project-memory",
|
|
186
|
+
"SPATIAL_MEMORY_LOG_LEVEL": "INFO",
|
|
187
|
+
"SPATIAL_MEMORY_DEFAULT_NAMESPACE": "project",
|
|
188
|
+
"SPATIAL_MEMORY_DEFAULT_IMPORTANCE": "0.5",
|
|
189
|
+
"SPATIAL_MEMORY_AUTO_DECAY_ENABLED": "true",
|
|
190
|
+
"SPATIAL_MEMORY_AUTO_DECAY_PERSIST_ENABLED": "true"
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Full Example: Claude Desktop
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"mcpServers": {
|
|
202
|
+
"spatial-memory": {
|
|
203
|
+
"command": "spatial-memory",
|
|
204
|
+
"env": {
|
|
205
|
+
"SPATIAL_MEMORY_MEMORY_PATH": "/Users/me/memories",
|
|
206
|
+
"SPATIAL_MEMORY_EMBEDDING_MODEL": "openai:text-embedding-3-small",
|
|
207
|
+
"SPATIAL_MEMORY_OPENAI_API_KEY": "sk-...",
|
|
208
|
+
"SPATIAL_MEMORY_AUTO_DECAY_ENABLED": "true"
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Advanced Settings
|
|
218
|
+
|
|
219
|
+
For power users, additional settings are available for:
|
|
220
|
+
|
|
221
|
+
- **Indexing**: `SPATIAL_MEMORY_VECTOR_INDEX_THRESHOLD`, `SPATIAL_MEMORY_AUTO_CREATE_INDEXES`, `SPATIAL_MEMORY_INDEX_TYPE`
|
|
222
|
+
- **Full-Text Search**: `SPATIAL_MEMORY_ENABLE_FTS_INDEX`, `SPATIAL_MEMORY_FTS_LANGUAGE`
|
|
223
|
+
- **Rate Limiting**: `SPATIAL_MEMORY_RATE_LIMIT_PER_AGENT_ENABLED`, `SPATIAL_MEMORY_RATE_LIMIT_PER_AGENT_RATE`
|
|
224
|
+
- **Circuit Breaker**: `SPATIAL_MEMORY_CIRCUIT_BREAKER_ENABLED`, `SPATIAL_MEMORY_CIRCUIT_BREAKER_FAILURE_THRESHOLD`
|
|
225
|
+
- **Caching**: `SPATIAL_MEMORY_RESPONSE_CACHE_ENABLED`, `SPATIAL_MEMORY_RESPONSE_CACHE_MAX_SIZE`
|
|
226
|
+
- **Manual Decay** (via `decay` tool): `SPATIAL_MEMORY_DECAY_DEFAULT_HALF_LIFE_DAYS`, `SPATIAL_MEMORY_DECAY_MIN_IMPORTANCE_FLOOR`
|
|
227
|
+
- **Export/Import**: `SPATIAL_MEMORY_EXPORT_ALLOWED_PATHS`, `SPATIAL_MEMORY_IMPORT_MAX_FILE_SIZE_MB`
|
|
228
|
+
|
|
229
|
+
See the full list in [`spatial_memory/config.py`](../spatial_memory/config.py).
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## Verifying Configuration
|
|
234
|
+
|
|
235
|
+
Check that your settings are applied by enabling debug logging:
|
|
236
|
+
|
|
237
|
+
```json
|
|
238
|
+
{
|
|
239
|
+
"env": {
|
|
240
|
+
"SPATIAL_MEMORY_LOG_LEVEL": "DEBUG"
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Then check the server logs for configuration values at startup.
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""Manual test script to verify auto-decay feature is working.
|
|
3
|
+
|
|
4
|
+
Run from the project root:
|
|
5
|
+
python scripts/test_auto_decay.py
|
|
6
|
+
|
|
7
|
+
This script demonstrates:
|
|
8
|
+
1. Decay calculation based on memory age
|
|
9
|
+
2. Access count slowing decay
|
|
10
|
+
3. Re-ranking of results by effective importance
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import sys
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
|
|
16
|
+
# Ensure we use the local development version, not installed package
|
|
17
|
+
project_root = Path(__file__).parent.parent
|
|
18
|
+
sys.path.insert(0, str(project_root))
|
|
19
|
+
|
|
20
|
+
from datetime import timedelta
|
|
21
|
+
|
|
22
|
+
from spatial_memory.core.models import AutoDecayConfig
|
|
23
|
+
from spatial_memory.core.utils import utc_now
|
|
24
|
+
from spatial_memory.services.decay_manager import DecayManager
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def print_header(title: str) -> None:
|
|
28
|
+
"""Print a section header."""
|
|
29
|
+
print(f"\n{'='*60}")
|
|
30
|
+
print(f" {title}")
|
|
31
|
+
print(f"{'='*60}\n")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def test_basic_decay() -> None:
|
|
35
|
+
"""Test that older memories have lower effective importance."""
|
|
36
|
+
print_header("Test 1: Basic Decay by Age")
|
|
37
|
+
|
|
38
|
+
config = AutoDecayConfig(
|
|
39
|
+
enabled=True,
|
|
40
|
+
persist_enabled=False,
|
|
41
|
+
half_life_days=30.0,
|
|
42
|
+
min_importance_floor=0.1,
|
|
43
|
+
access_weight=0.0, # Disable access count effect for this test
|
|
44
|
+
)
|
|
45
|
+
decay_manager = DecayManager(repository=None, config=config)
|
|
46
|
+
|
|
47
|
+
now = utc_now()
|
|
48
|
+
results = [
|
|
49
|
+
{
|
|
50
|
+
"id": "1",
|
|
51
|
+
"content": "Fresh memory (just now)",
|
|
52
|
+
"similarity": 0.9,
|
|
53
|
+
"importance": 1.0,
|
|
54
|
+
"last_accessed": now,
|
|
55
|
+
"access_count": 0,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "2",
|
|
59
|
+
"content": "30-day old memory (1 half-life)",
|
|
60
|
+
"similarity": 0.9,
|
|
61
|
+
"importance": 1.0,
|
|
62
|
+
"last_accessed": now - timedelta(days=30),
|
|
63
|
+
"access_count": 0,
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "3",
|
|
67
|
+
"content": "60-day old memory (2 half-lives)",
|
|
68
|
+
"similarity": 0.9,
|
|
69
|
+
"importance": 1.0,
|
|
70
|
+
"last_accessed": now - timedelta(days=60),
|
|
71
|
+
"access_count": 0,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"id": "4",
|
|
75
|
+
"content": "90-day old memory (3 half-lives)",
|
|
76
|
+
"similarity": 0.9,
|
|
77
|
+
"importance": 1.0,
|
|
78
|
+
"last_accessed": now - timedelta(days=90),
|
|
79
|
+
"access_count": 0,
|
|
80
|
+
},
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
processed = decay_manager.apply_decay_to_results(results, rerank=False)
|
|
84
|
+
|
|
85
|
+
print("All memories have same similarity (0.9) and stored importance (1.0)")
|
|
86
|
+
print("Half-life: 30 days\n")
|
|
87
|
+
|
|
88
|
+
for r in processed:
|
|
89
|
+
eff = r["effective_importance"]
|
|
90
|
+
decay_pct = (1.0 - eff) * 100
|
|
91
|
+
print(f" {r['content']}")
|
|
92
|
+
print(f" effective_importance: {eff:.4f} ({decay_pct:.1f}% decayed)")
|
|
93
|
+
print()
|
|
94
|
+
|
|
95
|
+
# Verify decay is working
|
|
96
|
+
assert processed[0]["effective_importance"] > processed[1]["effective_importance"]
|
|
97
|
+
assert processed[1]["effective_importance"] > processed[2]["effective_importance"]
|
|
98
|
+
assert processed[2]["effective_importance"] > processed[3]["effective_importance"]
|
|
99
|
+
print("PASS: Older memories have lower effective importance")
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def test_access_count_slows_decay() -> None:
|
|
103
|
+
"""Test that frequently accessed memories decay slower."""
|
|
104
|
+
print_header("Test 2: Access Count Slows Decay")
|
|
105
|
+
|
|
106
|
+
config = AutoDecayConfig(
|
|
107
|
+
enabled=True,
|
|
108
|
+
persist_enabled=False,
|
|
109
|
+
half_life_days=30.0,
|
|
110
|
+
min_importance_floor=0.1,
|
|
111
|
+
access_weight=0.3, # Each access adds 30% to half-life
|
|
112
|
+
)
|
|
113
|
+
decay_manager = DecayManager(repository=None, config=config)
|
|
114
|
+
|
|
115
|
+
now = utc_now()
|
|
116
|
+
past = now - timedelta(days=30) # 30 days ago
|
|
117
|
+
|
|
118
|
+
results = [
|
|
119
|
+
{
|
|
120
|
+
"id": "1",
|
|
121
|
+
"content": "Rarely accessed (0 times)",
|
|
122
|
+
"similarity": 0.9,
|
|
123
|
+
"importance": 1.0,
|
|
124
|
+
"last_accessed": past,
|
|
125
|
+
"access_count": 0,
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"id": "2",
|
|
129
|
+
"content": "Sometimes accessed (10 times)",
|
|
130
|
+
"similarity": 0.9,
|
|
131
|
+
"importance": 1.0,
|
|
132
|
+
"last_accessed": past,
|
|
133
|
+
"access_count": 10,
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"id": "3",
|
|
137
|
+
"content": "Frequently accessed (50 times)",
|
|
138
|
+
"similarity": 0.9,
|
|
139
|
+
"importance": 1.0,
|
|
140
|
+
"last_accessed": past,
|
|
141
|
+
"access_count": 50,
|
|
142
|
+
},
|
|
143
|
+
]
|
|
144
|
+
|
|
145
|
+
processed = decay_manager.apply_decay_to_results(results, rerank=False)
|
|
146
|
+
|
|
147
|
+
print("All memories are 30 days old with same similarity and stored importance")
|
|
148
|
+
print("access_weight: 0.3 (each access adds 30% to effective half-life)\n")
|
|
149
|
+
|
|
150
|
+
for r in processed:
|
|
151
|
+
eff = r["effective_importance"]
|
|
152
|
+
access = r["access_count"]
|
|
153
|
+
effective_half_life = 30.0 * (1.0 + 0.3 * access)
|
|
154
|
+
print(f" {r['content']}")
|
|
155
|
+
print(f" access_count: {access}")
|
|
156
|
+
print(f" effective_half_life: {effective_half_life:.1f} days")
|
|
157
|
+
print(f" effective_importance: {eff:.4f}")
|
|
158
|
+
print()
|
|
159
|
+
|
|
160
|
+
# Verify access count slows decay
|
|
161
|
+
assert processed[2]["effective_importance"] > processed[1]["effective_importance"]
|
|
162
|
+
assert processed[1]["effective_importance"] > processed[0]["effective_importance"]
|
|
163
|
+
print("PASS: Frequently accessed memories decay slower")
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def test_reranking() -> None:
|
|
167
|
+
"""Test that results are re-ranked by similarity * effective_importance."""
|
|
168
|
+
print_header("Test 3: Re-ranking by Adjusted Score")
|
|
169
|
+
|
|
170
|
+
config = AutoDecayConfig(
|
|
171
|
+
enabled=True,
|
|
172
|
+
persist_enabled=False,
|
|
173
|
+
half_life_days=30.0,
|
|
174
|
+
min_importance_floor=0.1,
|
|
175
|
+
access_weight=0.0,
|
|
176
|
+
)
|
|
177
|
+
decay_manager = DecayManager(repository=None, config=config)
|
|
178
|
+
|
|
179
|
+
now = utc_now()
|
|
180
|
+
|
|
181
|
+
# Old memory has higher similarity but will be outranked due to decay
|
|
182
|
+
results = [
|
|
183
|
+
{
|
|
184
|
+
"id": "old",
|
|
185
|
+
"content": "Old but highly similar",
|
|
186
|
+
"similarity": 0.95, # Higher similarity
|
|
187
|
+
"importance": 1.0,
|
|
188
|
+
"last_accessed": now - timedelta(days=60), # 60 days old
|
|
189
|
+
"access_count": 0,
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"id": "new",
|
|
193
|
+
"content": "Fresh but less similar",
|
|
194
|
+
"similarity": 0.70, # Lower similarity
|
|
195
|
+
"importance": 1.0,
|
|
196
|
+
"last_accessed": now, # Just accessed
|
|
197
|
+
"access_count": 0,
|
|
198
|
+
},
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
print("Before re-ranking (by similarity):")
|
|
202
|
+
print(f" 1. Old memory: similarity=0.95")
|
|
203
|
+
print(f" 2. Fresh memory: similarity=0.70\n")
|
|
204
|
+
|
|
205
|
+
processed = decay_manager.apply_decay_to_results(results, rerank=True)
|
|
206
|
+
|
|
207
|
+
print("After re-ranking (by similarity * effective_importance):")
|
|
208
|
+
for i, r in enumerate(processed, 1):
|
|
209
|
+
adj_score = r["similarity"] * r["effective_importance"]
|
|
210
|
+
print(f" {i}. {r['content']}")
|
|
211
|
+
print(f" similarity: {r['similarity']:.2f}")
|
|
212
|
+
print(f" effective_importance: {r['effective_importance']:.4f}")
|
|
213
|
+
print(f" adjusted_score: {adj_score:.4f}")
|
|
214
|
+
print()
|
|
215
|
+
|
|
216
|
+
# The fresh memory should now rank first despite lower similarity
|
|
217
|
+
assert processed[0]["id"] == "new", "Fresh memory should rank first after decay"
|
|
218
|
+
print("PASS: Fresh memory outranks old memory after decay adjustment")
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def test_minimum_floor() -> None:
|
|
222
|
+
"""Test that importance never goes below the minimum floor."""
|
|
223
|
+
print_header("Test 4: Minimum Importance Floor")
|
|
224
|
+
|
|
225
|
+
config = AutoDecayConfig(
|
|
226
|
+
enabled=True,
|
|
227
|
+
persist_enabled=False,
|
|
228
|
+
half_life_days=30.0,
|
|
229
|
+
min_importance_floor=0.1, # 10% floor
|
|
230
|
+
access_weight=0.0,
|
|
231
|
+
)
|
|
232
|
+
decay_manager = DecayManager(repository=None, config=config)
|
|
233
|
+
|
|
234
|
+
now = utc_now()
|
|
235
|
+
|
|
236
|
+
results = [
|
|
237
|
+
{
|
|
238
|
+
"id": "1",
|
|
239
|
+
"content": "Very old memory (1 year)",
|
|
240
|
+
"similarity": 0.9,
|
|
241
|
+
"importance": 1.0,
|
|
242
|
+
"last_accessed": now - timedelta(days=365),
|
|
243
|
+
"access_count": 0,
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"id": "2",
|
|
247
|
+
"content": "Ancient memory (5 years)",
|
|
248
|
+
"similarity": 0.9,
|
|
249
|
+
"importance": 1.0,
|
|
250
|
+
"last_accessed": now - timedelta(days=365 * 5),
|
|
251
|
+
"access_count": 0,
|
|
252
|
+
},
|
|
253
|
+
]
|
|
254
|
+
|
|
255
|
+
processed = decay_manager.apply_decay_to_results(results, rerank=False)
|
|
256
|
+
|
|
257
|
+
print(f"Minimum importance floor: {config.min_importance_floor}")
|
|
258
|
+
print()
|
|
259
|
+
|
|
260
|
+
for r in processed:
|
|
261
|
+
eff = r["effective_importance"]
|
|
262
|
+
print(f" {r['content']}")
|
|
263
|
+
print(f" effective_importance: {eff:.4f}")
|
|
264
|
+
print()
|
|
265
|
+
|
|
266
|
+
# Verify floor is respected
|
|
267
|
+
for r in processed:
|
|
268
|
+
assert r["effective_importance"] >= config.min_importance_floor
|
|
269
|
+
print(f"PASS: All effective_importance values >= {config.min_importance_floor}")
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def main() -> None:
|
|
273
|
+
"""Run all tests."""
|
|
274
|
+
print("\n" + "=" * 60)
|
|
275
|
+
print(" AUTO-DECAY FEATURE VERIFICATION")
|
|
276
|
+
print("=" * 60)
|
|
277
|
+
|
|
278
|
+
test_basic_decay()
|
|
279
|
+
test_access_count_slows_decay()
|
|
280
|
+
test_reranking()
|
|
281
|
+
test_minimum_floor()
|
|
282
|
+
|
|
283
|
+
print_header("ALL TESTS PASSED!")
|
|
284
|
+
print("The auto-decay feature is working correctly.\n")
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
if __name__ == "__main__":
|
|
288
|
+
main()
|
{spatial_memory_mcp-1.6.2 → spatial_memory_mcp-1.7.0}/spatial_memory/adapters/lancedb_repository.py
RENAMED
|
@@ -606,6 +606,8 @@ class LanceDBMemoryRepository:
|
|
|
606
606
|
tags=record.get("tags", []),
|
|
607
607
|
importance=record["importance"],
|
|
608
608
|
created_at=record["created_at"],
|
|
609
|
+
last_accessed=record.get("last_accessed"),
|
|
610
|
+
access_count=record.get("access_count", 0),
|
|
609
611
|
metadata=record.get("metadata", {}),
|
|
610
612
|
vector=vector,
|
|
611
613
|
)
|
|
@@ -593,6 +593,43 @@ class Settings(BaseSettings):
|
|
|
593
593
|
description="Maximum queue depth when backpressure is enabled",
|
|
594
594
|
)
|
|
595
595
|
|
|
596
|
+
# =========================================================================
|
|
597
|
+
# v1.6.3: Auto-Decay Settings
|
|
598
|
+
# =========================================================================
|
|
599
|
+
|
|
600
|
+
auto_decay_enabled: bool = Field(
|
|
601
|
+
default=True,
|
|
602
|
+
description="Enable automatic decay calculation during recall operations",
|
|
603
|
+
)
|
|
604
|
+
auto_decay_persist_enabled: bool = Field(
|
|
605
|
+
default=True,
|
|
606
|
+
description="Persist decay updates to database (disable for read-only scenarios)",
|
|
607
|
+
)
|
|
608
|
+
auto_decay_persist_batch_size: int = Field(
|
|
609
|
+
default=100,
|
|
610
|
+
ge=10,
|
|
611
|
+
le=1000,
|
|
612
|
+
description="Batch size for persisting decay updates to database",
|
|
613
|
+
)
|
|
614
|
+
auto_decay_persist_flush_interval_seconds: float = Field(
|
|
615
|
+
default=5.0,
|
|
616
|
+
ge=1.0,
|
|
617
|
+
le=60.0,
|
|
618
|
+
description="Interval between background flush operations for decay updates",
|
|
619
|
+
)
|
|
620
|
+
auto_decay_min_change_threshold: float = Field(
|
|
621
|
+
default=0.01,
|
|
622
|
+
ge=0.001,
|
|
623
|
+
le=0.1,
|
|
624
|
+
description="Minimum importance change to trigger database persistence (1% default)",
|
|
625
|
+
)
|
|
626
|
+
auto_decay_max_queue_size: int = Field(
|
|
627
|
+
default=10000,
|
|
628
|
+
ge=1000,
|
|
629
|
+
le=100000,
|
|
630
|
+
description="Maximum queue size for pending decay updates (backpressure control)",
|
|
631
|
+
)
|
|
632
|
+
|
|
596
633
|
model_config = {
|
|
597
634
|
"env_prefix": "SPATIAL_MEMORY_",
|
|
598
635
|
"env_file": ".env",
|