contextual-engine 0.9.5__tar.gz → 0.9.6__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.
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.gitignore +4 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/PKG-INFO +7 -11
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/doctor.py +4 -9
- contextual_engine-0.9.6/contextual/cli/commands/fetch.py +158 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/index.py +0 -5
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/install.py +1 -2
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/__init__.py +0 -2
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/base.py +1 -1
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/mcp_config.py +15 -7
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/indexing.py +15 -57
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/paths.py +18 -17
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/__init__.py +0 -2
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/retrieval_config.py +0 -8
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/core/errors.py +1 -2
- contextual_engine-0.9.6/contextual/core/memory.py +46 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/daemon_embed.py +6 -5
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/file_watcher.py +2 -30
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/incremental_indexer.py +132 -7
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/__init__.py +0 -37
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/_config.py +0 -5
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/index_writer.py +2 -1
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/pipeline.py +76 -14
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/processor.py +0 -86
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/__main__.py +6 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/memory_monitor.py +4 -25
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/auth.py +0 -2
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/ratelimit.py +9 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/warmup.py +3 -3
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/workspace.py +11 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/router.py +12 -6
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/server.py +34 -65
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/session_manager.py +79 -56
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/shim.py +95 -34
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/graph.py +49 -6
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/nexus.py +4 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/semantic.py +31 -3
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/system.py +3 -12
- contextual_engine-0.9.6/contextual/models/__init__.py +353 -0
- contextual_engine-0.9.6/contextual/models/_inference.py +15 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/models/allowlist.py +2 -3
- contextual_engine-0.9.6/contextual/models/base_embedder.py +23 -0
- contextual_engine-0.9.6/contextual/models/unified_embedder.py +353 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/__init__.py +3 -24
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/mmr.py +1 -46
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/pipeline.py +271 -137
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/ranker.py +2 -34
- contextual_engine-0.9.6/contextual/retrieval/structural_similarity.py +150 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/connection.py +11 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/fts.py +38 -1
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/lancedb_provider.py +84 -16
- contextual_engine-0.9.6/contextual/storage/migrations/m015_symbol_ngram.py +1 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/runner.py +18 -1
- contextual_engine-0.9.6/contextual/storage/migrations/solo/m015_symbol_ngram.py +154 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema.py +15 -4
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/blame_pipeline.py +9 -82
- contextual_engine-0.9.6/docs/SECURITY.md +116 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/pyproject.toml +12 -14
- contextual_engine-0.9.6/scripts/benchmark_golden.json +56 -0
- contextual_engine-0.9.6/scripts/run_benchmark.py +161 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/conftest.py +0 -15
- contextual_engine-0.9.6/tests/test_accuracy.py +90 -0
- contextual_engine-0.9.6/tests/test_async.py +121 -0
- contextual_engine-0.9.6/tests/test_mcp.py +155 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_retrieval.py +8 -54
- contextual_engine-0.9.6/tests/test_security.py +153 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_storage.py +171 -0
- contextual_engine-0.9.5/.cursor/rules/contextual.mdc +0 -87
- contextual_engine-0.9.5/contextual/cli/commands/fetch.py +0 -221
- contextual_engine-0.9.5/contextual/models/__init__.py +0 -575
- contextual_engine-0.9.5/contextual/models/_inference.py +0 -21
- contextual_engine-0.9.5/contextual/models/base_embedder.py +0 -72
- contextual_engine-0.9.5/contextual/models/reranker_model.py +0 -386
- contextual_engine-0.9.5/contextual/models/unified_embedder.py +0 -429
- contextual_engine-0.9.5/docs/SECURITY.md +0 -0
- contextual_engine-0.9.5/pytest.ini +0 -80
- contextual_engine-0.9.5/tests/test_accuracy.py +0 -23
- contextual_engine-0.9.5/tests/test_async.py +0 -23
- contextual_engine-0.9.5/tests/test_mcp.py +0 -33
- contextual_engine-0.9.5/tests/test_security.py +0 -23
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.contextualignore +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.github/workflows/ci.yml +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.github/workflows/release.yml +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/.mcp.json +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/LICENSE +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/README.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/__main__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/auth.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/client.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/initialisation.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/mcp.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/stats.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/commands/workspace.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/context.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/decorators.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/editor.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/cli/core/output.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/security_config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/global_/storage_config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/cache_config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/indexing_config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/observability_config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/workspace_config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/core/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/core/models.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/blame.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/hooks.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/git/incremental_git.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/dedup.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/extractor.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/integrator.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/resolver.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/staleness.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/store.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/graph/traversal.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/incremental/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/_ignore.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/chunker.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/docs_pipeline.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/merkle_tree.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/indexing/symbol_extractor.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/integrations/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/integrations/client_content.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/integrations/client_writer.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/_platform.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/access.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/bootstrap.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/daemon.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/audit.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/middleware/identity.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/_gcf.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/tools/temporal.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/mcp/workspace_registry.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/config.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/exporters.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/logging.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/retention.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/observability/tracer.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/context_assembler.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/retrieval/tokenizer.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/paths.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/sanitize.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/security/workspace.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/cache.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me001_orgs.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me002_org_members.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me003_teams.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me004_team_members.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me005_org_workspaces.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me006_workspace_permissions.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me007_idp_sync_log.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me008_org_policies.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me009_api_keys.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me010_org_audit_log.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/enterprise/me011_workspace_traceability.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m001_global.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m002_embeddings.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m003_temporal.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m004_graph.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m005_cache.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m006_logs.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m007_terminal_sessions.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m008_queue.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m009_swarm.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m010_task_force.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m011_reminders.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m013_temporal_l2.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/m014_nexus_foundation.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m001_global.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m002_embeddings.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m003_temporal.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m004_graph.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m005_cache.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m006_logs.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m007_terminal_sessions.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m008_queue.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m009_swarm.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m010_task_force.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m011_reminders.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m012_workspace_metadata.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m013_temporal_l2.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/solo/m014_nexus_foundation.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt001_orgs.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt002_org_members.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt003_teams.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt004_team_members.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt005_team_workspaces.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt006_workspace_permissions.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt007_team_audit_log.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/migrations/teams/mt008_workspace_traceability.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema_base.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema_ent.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/storage/schema_team.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/adr.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/context.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/query.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/temporal/velocity.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-001-lancedb-over-vec0.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-002-retry-exponential-backoff.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-003-blake3-deduplication.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-004-async-first-architecture.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-005-model-lineup.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ADRs/ADR-006-remove-bm25-k1-b-dead-config.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ARCHITECTURE.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/CHANGELOG.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DATABASE.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DEPLOYMENT.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DISTRIBUTIONS.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-mcp-cli-security-testing-distribution.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CHATGPT-DR-web-ui-experience.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-ai-agents-teams.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-competitive-landscape-market-analysis.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-core-architecture.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-mvp-phase0-technical-plan.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/CLAUDE-DR-strategic-briefing.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-analysis-extraction.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-graph-implementation.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-hybrid-retrieval-local-optimization.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-infrastructure-security.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-lance-specs.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-architecture.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-nexus-graph-engineering.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI-DR-vec0-vs-lancedb.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GEMINI_DR_extraction-optimisation.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/GRAPH_LAYER_OPEN_QUESTIONS_RESOLVED.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/KIMI-DR-tech-stack-optimization.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-L2-temporal.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-client-integration.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-indexing-optimisation.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-lancedb-implementation.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-local-data-infrastructure.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-config.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-mcp-security-hardening.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-models-pipelines.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-python-async-ai-pipelines.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/DRs/PERPLEXITY-DR-semantic-indexing.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/FRONTEND.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/GITHUB.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/INTEGRATIONS.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/MCP_TOOLS.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/MEMORY.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/PROJECT_MANAGEMENT.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/PROJECT_PHASES.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/RESOURCES.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/ROADMAP.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/TEAMS.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/TECHNICAL_SPEC.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/TESTING.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/docs/VERSION.MD +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/scripts/mcp_stress_test.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/README.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/fixtures/__init__.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/fixtures/sample_code.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/fixtures/sample_docs.md +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_architecture.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_behaviour.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_cache_stats.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_cli.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_flow.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_git.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_graph.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_graph_resolution_order.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_incremental.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_indexing.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_latency.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_mcp_hardening.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_observability.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_performance.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_query_cache_roundtrip.py +0 -0
- {contextual_engine-0.9.5 → contextual_engine-0.9.6}/tests/test_retry.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: contextual-engine
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.6
|
|
4
4
|
Summary: Temporal-first local code memory for AI tools via MCP
|
|
5
5
|
Project-URL: Homepage, https://contextuallabs.dev
|
|
6
6
|
Project-URL: Documentation, https://contextuallabs.dev/docs
|
|
@@ -125,16 +125,19 @@ Classifier: Environment :: Console
|
|
|
125
125
|
Classifier: Intended Audience :: Developers
|
|
126
126
|
Classifier: License :: Other/Proprietary License
|
|
127
127
|
Classifier: Operating System :: OS Independent
|
|
128
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
128
129
|
Classifier: Programming Language :: Python :: 3.12
|
|
129
130
|
Classifier: Programming Language :: Python :: 3.13
|
|
131
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
130
132
|
Classifier: Topic :: Software Development :: Libraries
|
|
131
133
|
Classifier: Topic :: Text Processing :: Indexing
|
|
132
134
|
Classifier: Typing :: Typed
|
|
133
|
-
Requires-Python: <3.
|
|
135
|
+
Requires-Python: <3.15,>=3.11
|
|
134
136
|
Requires-Dist: blake3>=0.4.1
|
|
137
|
+
Requires-Dist: datasketch>=1.6.4
|
|
135
138
|
Requires-Dist: docutils>=0.21
|
|
136
139
|
Requires-Dist: dulwich>=0.21
|
|
137
|
-
Requires-Dist:
|
|
140
|
+
Requires-Dist: fastembed>=0.4.2
|
|
138
141
|
Requires-Dist: fastmcp<4,>=3.2
|
|
139
142
|
Requires-Dist: httpx[http2]>=0.27.0
|
|
140
143
|
Requires-Dist: huggingface-hub>=0.23
|
|
@@ -153,8 +156,7 @@ Requires-Dist: pygit2>=1.15
|
|
|
153
156
|
Requires-Dist: python-frontmatter
|
|
154
157
|
Requires-Dist: rapidfuzz>=3
|
|
155
158
|
Requires-Dist: rich>=13.0
|
|
156
|
-
Requires-Dist:
|
|
157
|
-
Requires-Dist: sentence-transformers>=3.0
|
|
159
|
+
Requires-Dist: setproctitle>=1.3.0
|
|
158
160
|
Requires-Dist: simsimd<6,>=3.9
|
|
159
161
|
Requires-Dist: sqlglot>=20.0
|
|
160
162
|
Requires-Dist: starlette>=0.37
|
|
@@ -162,10 +164,7 @@ Requires-Dist: structlog>=25.4
|
|
|
162
164
|
Requires-Dist: tantivy>=0.20.1
|
|
163
165
|
Requires-Dist: tenacity>=8.0
|
|
164
166
|
Requires-Dist: tiktoken>=0.5
|
|
165
|
-
Requires-Dist: tokenizers<=0.23.0,>=0.19
|
|
166
167
|
Requires-Dist: tomli-w>=1.0.0
|
|
167
|
-
Requires-Dist: torch>=2.2
|
|
168
|
-
Requires-Dist: transformers<4.60,>=4.40
|
|
169
168
|
Requires-Dist: tree-sitter-language-pack>=0.7.2
|
|
170
169
|
Requires-Dist: typer<1.0,>=0.9
|
|
171
170
|
Requires-Dist: uvicorn>=0.27
|
|
@@ -178,9 +177,6 @@ Requires-Dist: build>=1.0; extra == 'dev'
|
|
|
178
177
|
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
179
178
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
180
179
|
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
181
|
-
Provides-Extra: mps
|
|
182
|
-
Requires-Dist: torch>=2.4.0; extra == 'mps'
|
|
183
|
-
Requires-Dist: torchvision>=0.19.0; extra == 'mps'
|
|
184
180
|
Provides-Extra: test
|
|
185
181
|
Requires-Dist: anyio[trio]>=4.3.0; extra == 'test'
|
|
186
182
|
Requires-Dist: freezegun>=1.5.0; extra == 'test'
|
|
@@ -14,7 +14,6 @@ from contextual.config.paths import (
|
|
|
14
14
|
LOG_DIR,
|
|
15
15
|
MODELS_DIR,
|
|
16
16
|
embed_model_present,
|
|
17
|
-
rerank_model_present,
|
|
18
17
|
workspace_config,
|
|
19
18
|
workspace_db,
|
|
20
19
|
workspace_logs,
|
|
@@ -85,14 +84,10 @@ async def doctor(
|
|
|
85
84
|
# 3. Models Check — check the actual weight dirs, not MODELS_DIR (which
|
|
86
85
|
# always contains cache/ after setup and would false-positive before fetch).
|
|
87
86
|
embed_ok = embed_model_present()
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
elif embed_ok and not rerank_ok:
|
|
93
|
-
model_detail = "Embed weights present. Reranker missing — run 'contextual fetch --rerank'."
|
|
94
|
-
else:
|
|
95
|
-
model_detail = "Embed weights missing or empty. Run 'contextual fetch'."
|
|
87
|
+
models_ok = embed_ok
|
|
88
|
+
model_detail = (
|
|
89
|
+
"Embed weights present." if embed_ok else "Embed weights missing. Run 'contextual fetch'."
|
|
90
|
+
)
|
|
96
91
|
checks.append(HealthCheck(name="Models", status=models_ok, detail=model_detail))
|
|
97
92
|
|
|
98
93
|
# 4. Daemon & Locks Check
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"""Global model fetch command for Contextual.
|
|
2
|
+
|
|
3
|
+
Downloads the fastembed/ONNX embedding model into ~/.contextual/models/
|
|
4
|
+
(the canonical global model directory) using fastembed's cache_dir parameter.
|
|
5
|
+
After download, computes and stores a BLAKE3 hash pin for integrity verification
|
|
6
|
+
on every subsequent model load.
|
|
7
|
+
|
|
8
|
+
The old sentence-transformers download path is fully removed.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
|
|
15
|
+
import structlog
|
|
16
|
+
import typer
|
|
17
|
+
|
|
18
|
+
from contextual.cli.core.decorators import register_command, require_config
|
|
19
|
+
from contextual.cli.core.output import (
|
|
20
|
+
model_download_progress,
|
|
21
|
+
print_error,
|
|
22
|
+
print_fetch_complete,
|
|
23
|
+
print_fetch_start,
|
|
24
|
+
)
|
|
25
|
+
from contextual.config.paths import GLOBAL_CONFIG, MODELS_DIR, ONNX_PIN_FILE, VERSION_FILE
|
|
26
|
+
from contextual.models.unified_embedder import _FASTEMBED_MODEL, _find_onnx_model_path
|
|
27
|
+
|
|
28
|
+
_EMBED_FRIENDLY = "Nomic Embed v1.5-Q (ONNX/fastembed)"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class FetchError(Exception):
|
|
32
|
+
"""Raised when a global model fetch cannot complete."""
|
|
33
|
+
|
|
34
|
+
def __init__(self, message: str, step: str | None = None, recoverable: bool = False) -> None:
|
|
35
|
+
super().__init__(message)
|
|
36
|
+
self.step = step
|
|
37
|
+
self.recoverable = recoverable
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _is_fastembed_model_cached() -> bool:
|
|
41
|
+
"""Return True if the ONNX model already exists in ~/.contextual/models/."""
|
|
42
|
+
onnx_path = _find_onnx_model_path(MODELS_DIR)
|
|
43
|
+
return onnx_path is not None and onnx_path.exists()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _verify_setup() -> None:
|
|
47
|
+
from contextual import __version__ as current_version
|
|
48
|
+
|
|
49
|
+
if not VERSION_FILE.exists():
|
|
50
|
+
print_error(
|
|
51
|
+
"Global setup not found.",
|
|
52
|
+
hint="Run: contextual setup",
|
|
53
|
+
)
|
|
54
|
+
raise typer.Exit(1)
|
|
55
|
+
|
|
56
|
+
if not GLOBAL_CONFIG.exists():
|
|
57
|
+
print_error(
|
|
58
|
+
"Global config missing.",
|
|
59
|
+
hint="Run: contextual setup",
|
|
60
|
+
)
|
|
61
|
+
raise typer.Exit(1)
|
|
62
|
+
|
|
63
|
+
installed = VERSION_FILE.read_text(encoding="utf-8").strip()
|
|
64
|
+
if installed != current_version:
|
|
65
|
+
print_error(
|
|
66
|
+
f"Version mismatch: installed={installed}, current={current_version}.",
|
|
67
|
+
hint="Run: contextual setup to upgrade.",
|
|
68
|
+
)
|
|
69
|
+
raise typer.Exit(1)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
async def download_embed_model() -> None:
|
|
73
|
+
"""Download the fastembed ONNX model into ~/.contextual/models/ and pin its hash."""
|
|
74
|
+
logger = structlog.get_logger()
|
|
75
|
+
|
|
76
|
+
with model_download_progress(_FASTEMBED_MODEL, size_hint="~130MB"):
|
|
77
|
+
try:
|
|
78
|
+
def _load() -> None:
|
|
79
|
+
from fastembed import TextEmbedding
|
|
80
|
+
MODELS_DIR.mkdir(parents=True, exist_ok=True)
|
|
81
|
+
# cache_dir routes fastembed to store weights under ~/.contextual/models/
|
|
82
|
+
# using HuggingFace Hub directory layout.
|
|
83
|
+
model = TextEmbedding(
|
|
84
|
+
model_name=_FASTEMBED_MODEL,
|
|
85
|
+
threads=1,
|
|
86
|
+
cache_dir=str(MODELS_DIR),
|
|
87
|
+
)
|
|
88
|
+
# One inference pass — verifies the ONNX session loads correctly.
|
|
89
|
+
list(model.embed(["warmup"], batch_size=1))
|
|
90
|
+
|
|
91
|
+
await asyncio.to_thread(_load)
|
|
92
|
+
except Exception as exc:
|
|
93
|
+
raise FetchError(
|
|
94
|
+
f"Failed to download fastembed model: {exc}", step="embed"
|
|
95
|
+
) from exc
|
|
96
|
+
|
|
97
|
+
# Pin the BLAKE3 hash of the ONNX file so _load_model() can verify integrity
|
|
98
|
+
# on every subsequent load without re-downloading.
|
|
99
|
+
try:
|
|
100
|
+
import blake3 as _blake3
|
|
101
|
+
|
|
102
|
+
onnx_path = _find_onnx_model_path(MODELS_DIR)
|
|
103
|
+
if onnx_path and onnx_path.exists():
|
|
104
|
+
pin = _blake3.blake3(onnx_path.read_bytes()).hexdigest()
|
|
105
|
+
ONNX_PIN_FILE.write_text(pin, encoding="utf-8")
|
|
106
|
+
logger.info(
|
|
107
|
+
"onnx_pin_written",
|
|
108
|
+
hash_prefix=pin[:16],
|
|
109
|
+
onnx_path=str(onnx_path),
|
|
110
|
+
)
|
|
111
|
+
else:
|
|
112
|
+
logger.warning("onnx_pin_skipped", reason="model_file_not_found_after_download")
|
|
113
|
+
except Exception as exc:
|
|
114
|
+
logger.warning("onnx_pin_write_failed", error=str(exc))
|
|
115
|
+
|
|
116
|
+
logger.info("fastembed_model_ready", model=_FASTEMBED_MODEL, cache_dir=str(MODELS_DIR))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
@register_command()
|
|
120
|
+
@require_config
|
|
121
|
+
def fetch(
|
|
122
|
+
embed: bool = typer.Option(False, "--embed", help="Download the Nomic embed model (ONNX)."),
|
|
123
|
+
all_: bool = typer.Option(False, "--all", help="Download all models (default)."),
|
|
124
|
+
) -> None:
|
|
125
|
+
"""Pre-download fastembed ONNX model weights into ~/.contextual/models/.
|
|
126
|
+
|
|
127
|
+
Model is stored in the global Contextual directory alongside the LanceDB
|
|
128
|
+
index and daemon config. Running this before the first `contextual index`
|
|
129
|
+
avoids an inline download during indexing and pins the BLAKE3 integrity hash.
|
|
130
|
+
"""
|
|
131
|
+
_verify_setup()
|
|
132
|
+
|
|
133
|
+
print_fetch_start([_EMBED_FRIENDLY])
|
|
134
|
+
|
|
135
|
+
downloaded: list[str] = []
|
|
136
|
+
already_present: list[str] = []
|
|
137
|
+
|
|
138
|
+
if _is_fastembed_model_cached():
|
|
139
|
+
already_present.append(_EMBED_FRIENDLY)
|
|
140
|
+
# Re-pin even if cached — updates stale or missing pin file.
|
|
141
|
+
try:
|
|
142
|
+
import blake3 as _blake3
|
|
143
|
+
|
|
144
|
+
onnx_path = _find_onnx_model_path(MODELS_DIR)
|
|
145
|
+
if onnx_path and onnx_path.exists():
|
|
146
|
+
pin = _blake3.blake3(onnx_path.read_bytes()).hexdigest()
|
|
147
|
+
ONNX_PIN_FILE.write_text(pin, encoding="utf-8")
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
150
|
+
else:
|
|
151
|
+
try:
|
|
152
|
+
asyncio.run(download_embed_model())
|
|
153
|
+
downloaded.append(_EMBED_FRIENDLY)
|
|
154
|
+
except FetchError as exc:
|
|
155
|
+
print_error(str(exc), hint="contextual fetch --embed")
|
|
156
|
+
raise typer.Exit(1) from exc
|
|
157
|
+
|
|
158
|
+
print_fetch_complete(downloaded, already_present)
|
|
@@ -95,16 +95,11 @@ async def index(
|
|
|
95
95
|
try:
|
|
96
96
|
with index_progress() as prog:
|
|
97
97
|
try:
|
|
98
|
-
# Suppress BLAKE3 pin warning during model load — pins are not
|
|
99
|
-
# registered until `contextual fetch` is run with a real model.
|
|
100
|
-
# The warning fires during SentenceTransformer.__init__, before
|
|
101
|
-
# the outer warnings.simplefilter("ignore") wrapper takes effect.
|
|
102
98
|
warnings.filterwarnings(
|
|
103
99
|
"ignore",
|
|
104
100
|
message=".*No BLAKE3 hash pins.*",
|
|
105
101
|
category=UserWarning,
|
|
106
102
|
)
|
|
107
|
-
# Reranker is search-only — never load at index time (~1.2GB saved).
|
|
108
103
|
await ensure_models_warm(models=["code", "docs"])
|
|
109
104
|
|
|
110
105
|
chunking_started = False
|
|
@@ -103,8 +103,7 @@ def _write_default_config() -> None:
|
|
|
103
103
|
'tier = "free"\n\n'
|
|
104
104
|
"[models]\n"
|
|
105
105
|
'embed_model = "nomic-ai/nomic-embed-text-v1.5"\n'
|
|
106
|
-
|
|
107
|
-
f'models_dir = "{MODELS_DIR}"\n'
|
|
106
|
+
f'models_dir = "{MODELS_DIR}"\n'
|
|
108
107
|
f'cache_dir = "{MODELS_CACHE_DIR}"\n\n'
|
|
109
108
|
"[storage]\n"
|
|
110
109
|
f'global_db_path = "{GLOBAL_DB_DIR}"\n'
|
|
@@ -19,7 +19,6 @@ from contextual.config.workspace.retrieval_config import (
|
|
|
19
19
|
BM25Config,
|
|
20
20
|
DenseConfig,
|
|
21
21
|
MMRConfig,
|
|
22
|
-
RerankerConfig,
|
|
23
22
|
RetrievalConfig,
|
|
24
23
|
)
|
|
25
24
|
from contextual.config.workspace.workspace_config import WorkspaceConfig
|
|
@@ -109,7 +108,6 @@ __all__ = [
|
|
|
109
108
|
"MMRConfig",
|
|
110
109
|
"ObservabilityConfig",
|
|
111
110
|
"PipelineConfig",
|
|
112
|
-
"RerankerConfig",
|
|
113
111
|
"RetrievalConfig",
|
|
114
112
|
"SecurityConfig",
|
|
115
113
|
"StorageConfig",
|
|
@@ -25,7 +25,7 @@ class ContextualConfig(BaseModel):
|
|
|
25
25
|
project_root: Absolute path to the project being indexed.
|
|
26
26
|
indexing: Indexing configuration for code and workspace files.
|
|
27
27
|
embedding: Embedding model configuration.
|
|
28
|
-
retrieval: Retrieval configuration for search
|
|
28
|
+
retrieval: Retrieval configuration for search (RRF fusion + MMR).
|
|
29
29
|
storage: Storage configuration for database and index paths.
|
|
30
30
|
security: Security configuration for filesystem and workspace policy.
|
|
31
31
|
"""
|
|
@@ -34,10 +34,16 @@ class DaemonConfig(BaseModel):
|
|
|
34
34
|
port: int = 9091 # must match _platform.WINDOWS_PORT/TCP_PORT
|
|
35
35
|
|
|
36
36
|
# Lifecycle
|
|
37
|
-
idle_sleep_minutes:
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
# idle_sleep_minutes: minutes of no incoming MCP requests before the daemon
|
|
38
|
+
# unloads the ONNX model and enters sleep state. Active shim connections
|
|
39
|
+
# (idle SSE sessions) do NOT prevent this — only actual HTTP requests reset
|
|
40
|
+
# the clock. die_after_sleep_hours: hours asleep before a clean SIGTERM
|
|
41
|
+
# exit. Total inactivity before full exit = idle_sleep_minutes +
|
|
42
|
+
# die_after_sleep_hours * 60. Set die_after_sleep_hours = 0 to never exit.
|
|
43
|
+
idle_sleep_minutes: int = 30 # Minutes of no requests before sleeping
|
|
44
|
+
die_after_sleep_hours: float = 1.0 # Hours asleep before clean exit (0 = never)
|
|
45
|
+
startup_timeout: float = 15.0 # Seconds to wait for the daemon to start serving
|
|
46
|
+
# (ONNX model loads in ~2-5s from ~/.contextual/models/)
|
|
41
47
|
|
|
42
48
|
# Rate limiting
|
|
43
49
|
rate_limit_per_minute: int = 120 # Max tool calls per minute per client
|
|
@@ -53,11 +59,13 @@ class DaemonConfig(BaseModel):
|
|
|
53
59
|
# Heap / memory trimmer
|
|
54
60
|
# When the daemon's physical footprint exceeds heap_trim_threshold_mb a
|
|
55
61
|
# hard trim fires (GC + malloc page return). If the footprint is still over
|
|
56
|
-
# the threshold on the next tick and no sessions are active,
|
|
57
|
-
#
|
|
62
|
+
# the threshold on the next tick and no sessions are active, the ONNX model
|
|
63
|
+
# session is unloaded (freed from memory). Set to 0 to disable.
|
|
64
|
+
# 1500 MB accounts for: ONNX session (~130 MB) + LanceDB PyArrow buffers
|
|
65
|
+
# (~400-800 MB active) + graph/cache overhead — triggers before OOM pressure.
|
|
58
66
|
heap_monitor_enabled: bool = True
|
|
59
67
|
heap_monitor_interval_seconds: int = 30
|
|
60
|
-
heap_trim_threshold_mb: int =
|
|
68
|
+
heap_trim_threshold_mb: int = 1500
|
|
61
69
|
|
|
62
70
|
# Logging
|
|
63
71
|
log_level: str = "INFO"
|
|
@@ -38,12 +38,11 @@ def resolve_local_model_path(model_ref: str) -> Path:
|
|
|
38
38
|
|
|
39
39
|
|
|
40
40
|
class EmbeddingConfig(BaseModel):
|
|
41
|
-
"""Embedding model configuration (
|
|
41
|
+
"""Embedding model configuration (nomic-embed-text-v1.5 via fastembed/ONNX Runtime since v0.10)."""
|
|
42
42
|
|
|
43
43
|
# Production models — all Apache-2.0 licensed, all 768d
|
|
44
44
|
code_model: str = Field(default=str(MODEL_CACHE_DIR / "nomic-embed-text-v1.5"))
|
|
45
45
|
docs_model: str = Field(default=str(MODEL_CACHE_DIR / "nomic-embed-text-v1.5"))
|
|
46
|
-
reranker_model: str = Field(default=str(MODEL_CACHE_DIR / "jina-reranker-v2-base-multilingual"))
|
|
47
46
|
dimension: int = Field(default=768)
|
|
48
47
|
batch_size: int = Field(default=16) # conservative default for 8GB unified memory Macs
|
|
49
48
|
max_context_length: int = Field(default=8192)
|
|
@@ -90,49 +89,17 @@ class IndexingConfig(BaseModel):
|
|
|
90
89
|
debounce_ms: int = Field(default=500) # file watcher debounce
|
|
91
90
|
|
|
92
91
|
|
|
93
|
-
class RerankerConfig(BaseModel):
|
|
94
|
-
"""Reranker service settings (BGE cross-encoder via sentence-transformers)."""
|
|
95
|
-
|
|
96
|
-
top_k: int = Field(default=15)
|
|
97
|
-
max_candidate_length: int = Field(default=2000)
|
|
98
|
-
batch_size: int = Field(default=15)
|
|
99
|
-
timeout_seconds: float = Field(default=10.0)
|
|
100
|
-
enable_retry: bool = Field(default=True)
|
|
101
|
-
fallback_on_error: bool = Field(default=True)
|
|
102
|
-
|
|
103
|
-
|
|
104
92
|
class SearchConfig(BaseModel):
|
|
105
|
-
"""Search pipeline settings (RRF +
|
|
93
|
+
"""Search pipeline settings (RRF + MMR)."""
|
|
106
94
|
|
|
107
95
|
rrf_k: int = Field(default=60)
|
|
108
96
|
bm25_weight: float = Field(default=0.4)
|
|
109
97
|
dense_weight: float = Field(default=0.6)
|
|
110
|
-
rrf_candidate_pool: int = Field(
|
|
111
|
-
default=35,
|
|
112
|
-
ge=10,
|
|
113
|
-
le=200,
|
|
114
|
-
description="Number of candidates retrieved before reranking.",
|
|
115
|
-
)
|
|
116
|
-
enable_reranker: bool = Field(default=False) # 124x latency overhead with no accuracy gain on MPS
|
|
117
|
-
rerank_top_k: int = Field(
|
|
118
|
-
default=10,
|
|
119
|
-
ge=5,
|
|
120
|
-
le=100,
|
|
121
|
-
description="Number of candidates passed to cross-encoder.",
|
|
122
|
-
)
|
|
98
|
+
rrf_candidate_pool: int = Field(default=35, ge=10, le=200)
|
|
123
99
|
mmr_lambda: float = Field(default=0.7)
|
|
124
100
|
mmr_max_per_file: int = Field(default=2)
|
|
125
101
|
mmr_max_per_symbol: int = Field(default=1)
|
|
126
102
|
|
|
127
|
-
@model_validator(mode="after")
|
|
128
|
-
def validate_pool_sizes(self) -> SearchConfig:
|
|
129
|
-
if self.rerank_top_k > self.rrf_candidate_pool:
|
|
130
|
-
raise ValueError(
|
|
131
|
-
f"rerank_top_k ({self.rerank_top_k}) cannot exceed "
|
|
132
|
-
f"rrf_candidate_pool ({self.rrf_candidate_pool})"
|
|
133
|
-
)
|
|
134
|
-
return self
|
|
135
|
-
|
|
136
103
|
|
|
137
104
|
class CacheConfig(BaseModel):
|
|
138
105
|
"""Embedding cache settings."""
|
|
@@ -150,11 +117,9 @@ class RetrievalConfig:
|
|
|
150
117
|
dense_candidates: int = 100
|
|
151
118
|
rrf_candidates: int = 50
|
|
152
119
|
rrf_k: int = 60
|
|
153
|
-
rrf_dense_weight: float = 0.
|
|
154
|
-
rrf_bm25_weight: float = 0.
|
|
155
|
-
|
|
156
|
-
reranker_top_n: int = 15
|
|
157
|
-
reranker_max_chunk_chars: int = 2000
|
|
120
|
+
rrf_dense_weight: float = 0.50
|
|
121
|
+
rrf_bm25_weight: float = 0.35
|
|
122
|
+
rrf_trigram_weight: float = 0.15
|
|
158
123
|
mmr_enabled: bool = True
|
|
159
124
|
mmr_lambda: float = 0.7
|
|
160
125
|
mmr_max_chunks_per_file: int = 2
|
|
@@ -168,6 +133,10 @@ class RetrievalConfig:
|
|
|
168
133
|
# distances. 10-20 recovers near-flat recall at a few ms cost.
|
|
169
134
|
refine_factor: int = 20
|
|
170
135
|
query_cache_ttl_seconds: int = 300
|
|
136
|
+
# Row count at which the incremental indexer triggers background IVF-PQ
|
|
137
|
+
# index maintenance. Below this threshold flat-scan ANN is fast enough
|
|
138
|
+
# and building IVF-PQ would waste CPU. Set to 0 to disable.
|
|
139
|
+
ann_index_row_threshold: int = 50_000
|
|
171
140
|
|
|
172
141
|
@classmethod
|
|
173
142
|
def from_toml(cls, config_path: Path) -> RetrievalConfig:
|
|
@@ -200,12 +169,8 @@ class RetrievalConfig:
|
|
|
200
169
|
rrf_bm25_weight=float(
|
|
201
170
|
retrieval_data.get("rrf_bm25_weight", defaults.rrf_bm25_weight)
|
|
202
171
|
),
|
|
203
|
-
|
|
204
|
-
retrieval_data.get("
|
|
205
|
-
),
|
|
206
|
-
reranker_top_n=int(retrieval_data.get("reranker_top_n", defaults.reranker_top_n)),
|
|
207
|
-
reranker_max_chunk_chars=int(
|
|
208
|
-
retrieval_data.get("reranker_max_chunk_chars", defaults.reranker_max_chunk_chars)
|
|
172
|
+
rrf_trigram_weight=float(
|
|
173
|
+
retrieval_data.get("rrf_trigram_weight", defaults.rrf_trigram_weight)
|
|
209
174
|
),
|
|
210
175
|
mmr_enabled=bool(retrieval_data.get("mmr_enabled", defaults.mmr_enabled)),
|
|
211
176
|
mmr_lambda=float(retrieval_data.get("mmr_lambda", defaults.mmr_lambda)),
|
|
@@ -224,6 +189,9 @@ class RetrievalConfig:
|
|
|
224
189
|
query_cache_ttl_seconds=int(
|
|
225
190
|
retrieval_data.get("query_cache_ttl_seconds", defaults.query_cache_ttl_seconds)
|
|
226
191
|
),
|
|
192
|
+
ann_index_row_threshold=int(
|
|
193
|
+
retrieval_data.get("ann_index_row_threshold", defaults.ann_index_row_threshold)
|
|
194
|
+
),
|
|
227
195
|
)
|
|
228
196
|
|
|
229
197
|
|
|
@@ -233,7 +201,6 @@ class PipelineConfig(BaseModel):
|
|
|
233
201
|
embedding: EmbeddingConfig = Field(default_factory=EmbeddingConfig)
|
|
234
202
|
chunking: ChunkingConfig = Field(default_factory=ChunkingConfig)
|
|
235
203
|
indexing: IndexingConfig = Field(default_factory=IndexingConfig)
|
|
236
|
-
reranker: RerankerConfig = Field(default_factory=RerankerConfig)
|
|
237
204
|
search: SearchConfig = Field(default_factory=SearchConfig)
|
|
238
205
|
cache: CacheConfig = Field(default_factory=CacheConfig)
|
|
239
206
|
|
|
@@ -247,8 +214,6 @@ class PipelineConfig(BaseModel):
|
|
|
247
214
|
cfg.embedding.code_model = v
|
|
248
215
|
if v := os.getenv("CONTEXTUAL_DOCS_MODEL"):
|
|
249
216
|
cfg.embedding.docs_model = v
|
|
250
|
-
if v := os.getenv("CONTEXTUAL_RERANKER_MODEL"):
|
|
251
|
-
cfg.embedding.reranker_model = v
|
|
252
217
|
if v := os.getenv("CONTEXTUAL_EMBED_DIM"):
|
|
253
218
|
cfg.embedding.dimension = int(v)
|
|
254
219
|
if v := os.getenv("CONTEXTUAL_EMBED_BATCH_SIZE"):
|
|
@@ -258,7 +223,6 @@ class PipelineConfig(BaseModel):
|
|
|
258
223
|
|
|
259
224
|
cfg.embedding.code_model = str(resolve_local_model_path(cfg.embedding.code_model))
|
|
260
225
|
cfg.embedding.docs_model = str(resolve_local_model_path(cfg.embedding.docs_model))
|
|
261
|
-
cfg.embedding.reranker_model = str(resolve_local_model_path(cfg.embedding.reranker_model))
|
|
262
226
|
|
|
263
227
|
# Indexing overrides
|
|
264
228
|
if v := os.getenv("CONTEXTUAL_BATCH_WRITE_SIZE"):
|
|
@@ -315,8 +279,6 @@ class RuntimeRetrievalConfig:
|
|
|
315
279
|
rrf_k: int = 60
|
|
316
280
|
rrf_dense_weight: float = 0.6
|
|
317
281
|
rrf_bm25_weight: float = 0.4
|
|
318
|
-
reranker_enabled: bool = False # 124x latency overhead with no accuracy gain on MPS
|
|
319
|
-
reranker_top_n: int = 15
|
|
320
282
|
mmr_lambda: float = 0.7
|
|
321
283
|
mmr_max_chunks_per_file: int = 2
|
|
322
284
|
mmr_max_chunks_per_symbol: int = 1
|
|
@@ -390,8 +352,6 @@ class ConfigLoader:
|
|
|
390
352
|
"rrf_k": 60,
|
|
391
353
|
"rrf_dense_weight": 0.6,
|
|
392
354
|
"rrf_bm25_weight": 0.4,
|
|
393
|
-
"reranker_enabled": False, # 124x latency overhead with no accuracy gain on MPS
|
|
394
|
-
"reranker_top_n": 15,
|
|
395
355
|
"mmr_lambda": 0.7,
|
|
396
356
|
"mmr_max_chunks_per_file": 2,
|
|
397
357
|
"mmr_max_chunks_per_symbol": 1,
|
|
@@ -435,8 +395,6 @@ class ConfigLoader:
|
|
|
435
395
|
env_overrides["retrieval"]["rrf_dense_weight"] = float(value)
|
|
436
396
|
if value := os.getenv("CONTEXTUAL_RRF_BM25_WEIGHT"):
|
|
437
397
|
env_overrides["retrieval"]["rrf_bm25_weight"] = float(value)
|
|
438
|
-
if value := os.getenv("CONTEXTUAL_RERANKER_TOP_N"):
|
|
439
|
-
env_overrides["retrieval"]["reranker_top_n"] = int(value)
|
|
440
398
|
if value := os.getenv("CONTEXTUAL_MMR_LAMBDA"):
|
|
441
399
|
env_overrides["retrieval"]["mmr_lambda"] = float(value)
|
|
442
400
|
if value := os.getenv("CONTEXTUAL_MMR_MAX_CHUNKS_PER_FILE"):
|
|
@@ -46,12 +46,13 @@ MCP_CONFIG_FILE = CONTEXTUAL_HOME / "mcp.json"
|
|
|
46
46
|
WORKSPACES_JSON_PATH = CONTEXTUAL_HOME / "workspaces.json"
|
|
47
47
|
LOG_DIR = Path.home() / ".local" / "state" / "contextual" / "logs"
|
|
48
48
|
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
# fastembed Hub cache directory for the embed model.
|
|
50
|
+
# `contextual fetch` downloads into MODELS_DIR using fastembed's cache_dir
|
|
51
|
+
# parameter; fastembed mirrors HuggingFace Hub layout under that root.
|
|
52
|
+
EMBED_MODEL_DIR = MODELS_DIR / "models--nomic-ai--nomic-embed-text-v1.5"
|
|
53
|
+
|
|
54
|
+
# BLAKE3 hash pin file written by `contextual fetch` and verified on model load.
|
|
55
|
+
ONNX_PIN_FILE = MODELS_DIR / ".onnx_pin"
|
|
55
56
|
|
|
56
57
|
|
|
57
58
|
def _dir_has_content(path: Path) -> bool:
|
|
@@ -62,17 +63,17 @@ def _dir_has_content(path: Path) -> bool:
|
|
|
62
63
|
|
|
63
64
|
|
|
64
65
|
def embed_model_present() -> bool:
|
|
65
|
-
"""True when the embed model
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
66
|
+
"""True when the ONNX embed model has been fetched into ~/.contextual/models/."""
|
|
67
|
+
if not _dir_has_content(EMBED_MODEL_DIR):
|
|
68
|
+
return False
|
|
69
|
+
snapshots = EMBED_MODEL_DIR / "snapshots"
|
|
70
|
+
if not snapshots.is_dir():
|
|
71
|
+
return False
|
|
72
|
+
return any(
|
|
73
|
+
(s / "onnx" / "model_quantized.onnx").exists()
|
|
74
|
+
for s in snapshots.iterdir()
|
|
75
|
+
if s.is_dir()
|
|
76
|
+
)
|
|
76
77
|
|
|
77
78
|
|
|
78
79
|
# ── Workspace subdirectories ──────────
|
|
@@ -5,7 +5,6 @@ from contextual.config.workspace.retrieval_config import (
|
|
|
5
5
|
BM25Config,
|
|
6
6
|
DenseConfig,
|
|
7
7
|
MMRConfig,
|
|
8
|
-
RerankerConfig,
|
|
9
8
|
RetrievalConfig,
|
|
10
9
|
RRFConfig,
|
|
11
10
|
)
|
|
@@ -20,7 +19,6 @@ __all__ = [
|
|
|
20
19
|
"MMRConfig",
|
|
21
20
|
"ObservabilityConfig",
|
|
22
21
|
"RRFConfig",
|
|
23
|
-
"RerankerConfig",
|
|
24
22
|
"RetrievalConfig",
|
|
25
23
|
"WorkspaceConfig",
|
|
26
24
|
]
|
{contextual_engine-0.9.5 → contextual_engine-0.9.6}/contextual/config/workspace/retrieval_config.py
RENAMED
|
@@ -24,13 +24,6 @@ class RRFConfig(BaseModel):
|
|
|
24
24
|
bm25_weight: float = 0.4
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
class RerankerConfig(BaseModel):
|
|
28
|
-
"""Cross-encoder reranking settings."""
|
|
29
|
-
|
|
30
|
-
top_n: int = 15
|
|
31
|
-
max_chunk_chars: int = 2000
|
|
32
|
-
|
|
33
|
-
|
|
34
27
|
class MMRConfig(BaseModel):
|
|
35
28
|
"""MMR diversity settings."""
|
|
36
29
|
|
|
@@ -45,7 +38,6 @@ class RetrievalConfig(BaseModel):
|
|
|
45
38
|
bm25: BM25Config = BM25Config()
|
|
46
39
|
dense: DenseConfig = DenseConfig()
|
|
47
40
|
rrf: RRFConfig = RRFConfig()
|
|
48
|
-
reranker: RerankerConfig = RerankerConfig()
|
|
49
41
|
mmr: MMRConfig = MMRConfig()
|
|
50
42
|
final_top_k: int = 10
|
|
51
43
|
max_context_tokens: int = 8000
|
|
@@ -138,7 +138,6 @@ class ErrorCode(StrEnum):
|
|
|
138
138
|
RETRIEVAL_BM25_FAILED = "retrieval_bm25_failed"
|
|
139
139
|
RETRIEVAL_DENSE_SEARCH_FAILED = "retrieval_dense_search_failed"
|
|
140
140
|
RETRIEVAL_FUSION_FAILED = "retrieval_fusion_failed"
|
|
141
|
-
RETRIEVAL_RERANK_FAILED = "retrieval_rerank_failed"
|
|
142
141
|
RETRIEVAL_HYDRATION_FAILED = "retrieval_hydration_failed"
|
|
143
142
|
RETRIEVAL_NO_RESULTS = "retrieval_no_results" # Not an error, informational
|
|
144
143
|
|
|
@@ -315,7 +314,7 @@ class GitError(ContextualExceptionError):
|
|
|
315
314
|
|
|
316
315
|
|
|
317
316
|
class RetrievalError(ContextualExceptionError):
|
|
318
|
-
"""Errors from the retrieval pipeline (search, fusion,
|
|
317
|
+
"""Errors from the retrieval pipeline (search, RRF fusion, MMR)."""
|
|
319
318
|
|
|
320
319
|
|
|
321
320
|
class SecurityError(ContextualExceptionError):
|