context-bridge-memory 0.1.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.
- context_bridge_memory-0.1.0/.dockerignore +20 -0
- context_bridge_memory-0.1.0/.env.example +127 -0
- context_bridge_memory-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +31 -0
- context_bridge_memory-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- context_bridge_memory-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +24 -0
- context_bridge_memory-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +19 -0
- context_bridge_memory-0.1.0/.github/workflows/ci.yml +43 -0
- context_bridge_memory-0.1.0/.github/workflows/release.yml +66 -0
- context_bridge_memory-0.1.0/.gitignore +29 -0
- context_bridge_memory-0.1.0/.pre-commit-config.yaml +16 -0
- context_bridge_memory-0.1.0/.release-trigger +1 -0
- context_bridge_memory-0.1.0/CHANGELOG.md +96 -0
- context_bridge_memory-0.1.0/CODE_OF_CONDUCT.md +37 -0
- context_bridge_memory-0.1.0/CONTRIBUTING.md +68 -0
- context_bridge_memory-0.1.0/Dockerfile +43 -0
- context_bridge_memory-0.1.0/LICENSE +201 -0
- context_bridge_memory-0.1.0/Makefile +33 -0
- context_bridge_memory-0.1.0/NOTICE +6 -0
- context_bridge_memory-0.1.0/PKG-INFO +485 -0
- context_bridge_memory-0.1.0/README.md +443 -0
- context_bridge_memory-0.1.0/RELEASE_NOTES_v0.1.0.md +50 -0
- context_bridge_memory-0.1.0/SECURITY.md +30 -0
- context_bridge_memory-0.1.0/alembic/env.py +53 -0
- context_bridge_memory-0.1.0/alembic/script.py.mako +26 -0
- context_bridge_memory-0.1.0/alembic/versions/0001_initial.py +44 -0
- context_bridge_memory-0.1.0/alembic/versions/0002_parent_documents.py +33 -0
- context_bridge_memory-0.1.0/alembic/versions/0003_cognitive_layer.py +74 -0
- context_bridge_memory-0.1.0/alembic/versions/0004_collective_learning.py +55 -0
- context_bridge_memory-0.1.0/alembic/versions/0005_entity_aliases.py +36 -0
- context_bridge_memory-0.1.0/alembic/versions/0006_lessons.py +42 -0
- context_bridge_memory-0.1.0/alembic.ini +39 -0
- context_bridge_memory-0.1.0/deploy/grafana/dashboards/context-bridge.json +193 -0
- context_bridge_memory-0.1.0/deploy/grafana/provisioning/dashboards/provider.yml +12 -0
- context_bridge_memory-0.1.0/deploy/grafana/provisioning/datasources/datasource.yml +10 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/.helmignore +6 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/Chart.yaml +14 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/NOTES.txt +18 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/_helpers.tpl +33 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/configmap.yaml +10 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/deployment.yaml +67 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/hpa.yaml +22 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/ingress.yaml +37 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/service.yaml +15 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/templates/serviceaccount.yaml +8 -0
- context_bridge_memory-0.1.0/deploy/helm/context-bridge/values.yaml +83 -0
- context_bridge_memory-0.1.0/deploy/prometheus/prometheus.yml +9 -0
- context_bridge_memory-0.1.0/docker-compose.observability.yml +31 -0
- context_bridge_memory-0.1.0/docker-compose.yml +46 -0
- context_bridge_memory-0.1.0/docs/assets/demo.gif +0 -0
- context_bridge_memory-0.1.0/examples/quickstart.py +117 -0
- context_bridge_memory-0.1.0/pyproject.toml +85 -0
- context_bridge_memory-0.1.0/src/context_bridge/__init__.py +5 -0
- context_bridge_memory-0.1.0/src/context_bridge/__main__.py +21 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/__init__.py +1 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/access.py +67 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/app.py +187 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/deps.py +142 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/metrics.py +58 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/__init__.py +1 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/conflicts.py +51 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/graph.py +61 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/health.py +49 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/insights.py +66 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/learning.py +95 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/lessons.py +88 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/maintenance.py +76 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/memory.py +221 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/quality.py +23 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/routes/sessions.py +68 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/schemas.py +370 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/security.py +137 -0
- context_bridge_memory-0.1.0/src/context_bridge/api/tracing.py +42 -0
- context_bridge_memory-0.1.0/src/context_bridge/benchmark.py +120 -0
- context_bridge_memory-0.1.0/src/context_bridge/config.py +159 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/__init__.py +1 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/chunking/__init__.py +18 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/chunking/base.py +63 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/chunking/recursive.py +58 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/chunking/semantic.py +73 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/embeddings/__init__.py +46 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/embeddings/base.py +43 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/embeddings/cohere_embedder.py +59 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/embeddings/fastembed_embedder.py +63 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/embeddings/hashing.py +80 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/embeddings/openai_embedder.py +63 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/events.py +72 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/graph/__init__.py +12 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/graph/extractor.py +86 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/graph/resolver.py +22 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/__init__.py +8 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/consolidation.py +38 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/contradiction.py +104 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/manager.py +1104 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/policy.py +40 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/redaction.py +47 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/salience.py +123 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/memory/summarizer.py +174 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/models.py +139 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/retrieval/__init__.py +8 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/retrieval/budget.py +73 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/retrieval/mmr.py +69 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/retrieval/reranker.py +96 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/retrieval/retriever.py +175 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/tracing.py +32 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/vectorstore/__init__.py +23 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/vectorstore/base.py +63 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/vectorstore/qdrant_store.py +333 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/working/__init__.py +22 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/working/base.py +26 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/working/memory_store.py +33 -0
- context_bridge_memory-0.1.0/src/context_bridge/core/working/redis_store.py +34 -0
- context_bridge_memory-0.1.0/src/context_bridge/db/__init__.py +51 -0
- context_bridge_memory-0.1.0/src/context_bridge/db/models.py +298 -0
- context_bridge_memory-0.1.0/src/context_bridge/db/repository.py +633 -0
- context_bridge_memory-0.1.0/src/context_bridge/db/session.py +37 -0
- context_bridge_memory-0.1.0/src/context_bridge/py.typed +0 -0
- context_bridge_memory-0.1.0/src/context_bridge/sdk/__init__.py +7 -0
- context_bridge_memory-0.1.0/src/context_bridge/sdk/client.py +341 -0
- context_bridge_memory-0.1.0/src/context_bridge/tokenizer.py +52 -0
- context_bridge_memory-0.1.0/tests/__init__.py +0 -0
- context_bridge_memory-0.1.0/tests/conftest.py +58 -0
- context_bridge_memory-0.1.0/tests/integration/__init__.py +0 -0
- context_bridge_memory-0.1.0/tests/integration/test_api.py +64 -0
- context_bridge_memory-0.1.0/tests/integration/test_api_extra.py +97 -0
- context_bridge_memory-0.1.0/tests/integration/test_belief_distill_explain.py +128 -0
- context_bridge_memory-0.1.0/tests/integration/test_belief_distill_explain_api.py +28 -0
- context_bridge_memory-0.1.0/tests/integration/test_benchmark.py +21 -0
- context_bridge_memory-0.1.0/tests/integration/test_cognitive.py +102 -0
- context_bridge_memory-0.1.0/tests/integration/test_cognitive_api.py +49 -0
- context_bridge_memory-0.1.0/tests/integration/test_collective.py +73 -0
- context_bridge_memory-0.1.0/tests/integration/test_collective_api.py +56 -0
- context_bridge_memory-0.1.0/tests/integration/test_data_management.py +63 -0
- context_bridge_memory-0.1.0/tests/integration/test_insights.py +111 -0
- context_bridge_memory-0.1.0/tests/integration/test_insights_api.py +35 -0
- context_bridge_memory-0.1.0/tests/integration/test_lessons.py +105 -0
- context_bridge_memory-0.1.0/tests/integration/test_lessons_api.py +74 -0
- context_bridge_memory-0.1.0/tests/integration/test_maintenance.py +43 -0
- context_bridge_memory-0.1.0/tests/integration/test_memory_flow.py +112 -0
- context_bridge_memory-0.1.0/tests/integration/test_metrics.py +25 -0
- context_bridge_memory-0.1.0/tests/integration/test_ontology_quality.py +93 -0
- context_bridge_memory-0.1.0/tests/integration/test_ontology_quality_api.py +41 -0
- context_bridge_memory-0.1.0/tests/integration/test_ops.py +97 -0
- context_bridge_memory-0.1.0/tests/integration/test_ops_api.py +42 -0
- context_bridge_memory-0.1.0/tests/integration/test_rbac.py +92 -0
- context_bridge_memory-0.1.0/tests/integration/test_reranker_smoke.py +48 -0
- context_bridge_memory-0.1.0/tests/integration/test_salient_temporal.py +67 -0
- context_bridge_memory-0.1.0/tests/integration/test_sdk_extended.py +56 -0
- context_bridge_memory-0.1.0/tests/integration/test_security.py +68 -0
- context_bridge_memory-0.1.0/tests/integration/test_streaming.py +37 -0
- context_bridge_memory-0.1.0/tests/unit/__init__.py +0 -0
- context_bridge_memory-0.1.0/tests/unit/test_budget.py +47 -0
- context_bridge_memory-0.1.0/tests/unit/test_chunking.py +40 -0
- context_bridge_memory-0.1.0/tests/unit/test_cognitive_units.py +66 -0
- context_bridge_memory-0.1.0/tests/unit/test_events.py +18 -0
- context_bridge_memory-0.1.0/tests/unit/test_mmr.py +38 -0
- context_bridge_memory-0.1.0/tests/unit/test_policy.py +44 -0
- context_bridge_memory-0.1.0/tests/unit/test_providers.py +42 -0
- context_bridge_memory-0.1.0/tests/unit/test_resolver.py +28 -0
- context_bridge_memory-0.1.0/tests/unit/test_rrf.py +25 -0
- context_bridge_memory-0.1.0/tests/unit/test_salience.py +31 -0
- context_bridge_memory-0.1.0/tests/unit/test_semantic_chunking.py +32 -0
- context_bridge_memory-0.1.0/tests/unit/test_summarizer.py +38 -0
- context_bridge_memory-0.1.0/tests/unit/test_tokenizer.py +27 -0
- context_bridge_memory-0.1.0/tests/unit/test_tracing.py +27 -0
- context_bridge_memory-0.1.0/tests/unit/test_working_memory.py +42 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
.git
|
|
2
|
+
.github
|
|
3
|
+
.venv
|
|
4
|
+
venv
|
|
5
|
+
__pycache__
|
|
6
|
+
*.pyc
|
|
7
|
+
.pytest_cache
|
|
8
|
+
.mypy_cache
|
|
9
|
+
.ruff_cache
|
|
10
|
+
.coverage
|
|
11
|
+
htmlcov
|
|
12
|
+
tests
|
|
13
|
+
*.db
|
|
14
|
+
*.sqlite3
|
|
15
|
+
.env
|
|
16
|
+
qdrant_storage
|
|
17
|
+
.fastembed_cache
|
|
18
|
+
docker-compose.yml
|
|
19
|
+
Dockerfile
|
|
20
|
+
.dockerignore
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# --- API ---
|
|
2
|
+
API_HOST=0.0.0.0
|
|
3
|
+
API_PORT=8000
|
|
4
|
+
LOG_LEVEL=info
|
|
5
|
+
|
|
6
|
+
# --- Security ---
|
|
7
|
+
# Comma-separated API keys sent via the X-API-Key header. Empty = auth disabled.
|
|
8
|
+
API_KEYS=
|
|
9
|
+
# Optional per-key namespace allow-list as JSON. "*" or omission = all namespaces.
|
|
10
|
+
# Example: {"team-a-key": ["team-a"], "ops-key": ["*"]}
|
|
11
|
+
API_KEY_NAMESPACES=
|
|
12
|
+
# Optional RBAC policies (namespace globs + read/write permissions) as JSON.
|
|
13
|
+
# Example: {"reader": {"namespaces": ["team-a*"], "permissions": ["read"]}}
|
|
14
|
+
API_KEY_POLICIES=
|
|
15
|
+
# Per-identity requests per minute on data-plane routes. 0 = limiter disabled.
|
|
16
|
+
RATE_LIMIT_PER_MINUTE=0
|
|
17
|
+
# Rate limiter backend: "memory" (single replica) or "redis" (shared/horizontal).
|
|
18
|
+
RATE_LIMIT_BACKEND=memory
|
|
19
|
+
# CORS allowed origins (comma-separated, or "*").
|
|
20
|
+
CORS_ALLOW_ORIGINS=*
|
|
21
|
+
|
|
22
|
+
# --- Observability ---
|
|
23
|
+
# Expose Prometheus metrics at /metrics and record request latency.
|
|
24
|
+
METRICS_ENABLED=true
|
|
25
|
+
# OpenTelemetry tracing (requires the 'otel' extra). Exports spans via OTLP.
|
|
26
|
+
TRACING_ENABLED=false
|
|
27
|
+
OTEL_SERVICE_NAME=context-bridge
|
|
28
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=
|
|
29
|
+
|
|
30
|
+
# --- Vector store (Qdrant) ---
|
|
31
|
+
# Use ":memory:" for an ephemeral in-process store (great for local dev / tests),
|
|
32
|
+
# or a URL such as http://localhost:6333 for a running Qdrant instance.
|
|
33
|
+
QDRANT_URL=:memory:
|
|
34
|
+
QDRANT_API_KEY=
|
|
35
|
+
QDRANT_COLLECTION=context_bridge
|
|
36
|
+
|
|
37
|
+
# --- Embeddings ---
|
|
38
|
+
# Provider: "hashing" (offline), "fastembed" (local), "openai", or "cohere".
|
|
39
|
+
EMBED_PROVIDER=hashing
|
|
40
|
+
EMBED_DENSE_MODEL=BAAI/bge-small-en-v1.5
|
|
41
|
+
EMBED_SPARSE_MODEL=Qdrant/bm25
|
|
42
|
+
EMBED_DIM=384
|
|
43
|
+
|
|
44
|
+
# External provider credentials (used by EMBED_PROVIDER/RERANK_PROVIDER openai|cohere)
|
|
45
|
+
OPENAI_API_KEY=
|
|
46
|
+
OPENAI_BASE_URL=
|
|
47
|
+
COHERE_API_KEY=
|
|
48
|
+
|
|
49
|
+
# --- Reranker ---
|
|
50
|
+
# Provider: "identity" (no-op, keeps fusion order) or "fastembed".
|
|
51
|
+
RERANK_PROVIDER=identity
|
|
52
|
+
RERANK_MODEL=Xenova/ms-marco-MiniLM-L-6-v2
|
|
53
|
+
|
|
54
|
+
# --- Summarizer ---
|
|
55
|
+
# Provider: "extractive" (no model) or "llm" (OpenAI-compatible chat endpoint;
|
|
56
|
+
# falls back to extractive on error). Works with any local/self-hosted server.
|
|
57
|
+
SUMMARIZER_PROVIDER=extractive
|
|
58
|
+
LLM_BASE_URL=http://localhost:11434/v1
|
|
59
|
+
LLM_API_KEY=
|
|
60
|
+
LLM_MODEL=qwen2.5
|
|
61
|
+
LLM_TIMEOUT=30
|
|
62
|
+
LLM_MAX_TOKENS=512
|
|
63
|
+
|
|
64
|
+
# --- Structured / episodic store ---
|
|
65
|
+
DATABASE_URL=sqlite+pysqlite:///./context_bridge.db
|
|
66
|
+
|
|
67
|
+
# --- Working memory ---
|
|
68
|
+
# Provider: "memory" (in-process) or "redis".
|
|
69
|
+
WORKING_PROVIDER=memory
|
|
70
|
+
REDIS_URL=redis://localhost:6379/0
|
|
71
|
+
WORKING_TTL_SECONDS=3600
|
|
72
|
+
|
|
73
|
+
# --- Retrieval defaults ---
|
|
74
|
+
DEFAULT_TOP_K=8
|
|
75
|
+
DEFAULT_TOKEN_BUDGET=2048
|
|
76
|
+
PREFETCH_LIMIT=50
|
|
77
|
+
MMR_LAMBDA=0.6
|
|
78
|
+
|
|
79
|
+
# --- Write policy ---
|
|
80
|
+
DEDUP_THRESHOLD=0.95
|
|
81
|
+
MIN_CONFIDENCE=0.0
|
|
82
|
+
CHUNK_SIZE_TOKENS=256
|
|
83
|
+
CHUNK_OVERLAP_TOKENS=32
|
|
84
|
+
|
|
85
|
+
# --- Maintenance ---
|
|
86
|
+
# Background TTL sweep interval in seconds (0 disables the periodic job).
|
|
87
|
+
SWEEP_INTERVAL_SECONDS=0
|
|
88
|
+
# Full housekeeping cycle interval in seconds (0 disables); runs per-namespace
|
|
89
|
+
# upkeep (auto-resolve / consolidate / lesson distillation) plus a TTL sweep.
|
|
90
|
+
MAINTENANCE_INTERVAL_SECONDS=0
|
|
91
|
+
MAINTENANCE_AUTO_RESOLVE=true
|
|
92
|
+
MAINTENANCE_CONSOLIDATE=false
|
|
93
|
+
MAINTENANCE_DISTILL_LESSONS=false
|
|
94
|
+
|
|
95
|
+
# --- Event webhooks ---
|
|
96
|
+
# Comma-separated URLs notified (best-effort) of notable memory events.
|
|
97
|
+
WEBHOOK_URLS=
|
|
98
|
+
WEBHOOK_TIMEOUT_SECONDS=5.0
|
|
99
|
+
|
|
100
|
+
# --- Cognitive layer ---
|
|
101
|
+
# Mask secrets/PII before content enters the shared pool.
|
|
102
|
+
REDACT_PII=false
|
|
103
|
+
# How strongly outcome feedback re-ranks recall (0 disables).
|
|
104
|
+
FEEDBACK_WEIGHT=0.15
|
|
105
|
+
# Reflective consolidation: cluster size + similarity threshold.
|
|
106
|
+
CONSOLIDATION_MIN_CLUSTER=3
|
|
107
|
+
CONSOLIDATION_SIMILARITY=0.83
|
|
108
|
+
# Flag contradictions between memories on write.
|
|
109
|
+
DETECT_CONTRADICTIONS=false
|
|
110
|
+
CONTRADICTION_SIMILARITY=0.80
|
|
111
|
+
# Extract an entity/relation knowledge graph from writes.
|
|
112
|
+
GRAPH_EXTRACTION=false
|
|
113
|
+
# Failure memory: raise relevant lessons from past mistakes on recall.
|
|
114
|
+
LESSONS_ENABLED=true
|
|
115
|
+
LESSONS_TOP_K=3
|
|
116
|
+
# Minimum trigger<->query similarity to surface a lesson.
|
|
117
|
+
LESSONS_MIN_SCORE=0.20
|
|
118
|
+
# Auto-distil lessons by clustering memories implicated in failures.
|
|
119
|
+
LESSON_DISTILL_MIN_CLUSTER=2
|
|
120
|
+
LESSON_DISTILL_SIMILARITY=0.83
|
|
121
|
+
# Belief revision: demote memories that lose a contradiction.
|
|
122
|
+
BELIEF_REVISION=true
|
|
123
|
+
CONFLICT_LOSER_DECAY=0.5
|
|
124
|
+
# How strongly recall demotes low-confidence memories (0 disables).
|
|
125
|
+
CONFIDENCE_WEIGHT=0.5
|
|
126
|
+
# Authority gap (trust + feedback) needed to auto-close a contradiction.
|
|
127
|
+
AUTO_RESOLVE_MIN_GAP=0.3
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a problem with Context Bridge
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: what-happened
|
|
7
|
+
attributes:
|
|
8
|
+
label: What happened?
|
|
9
|
+
description: A clear description of the bug, including what you expected.
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: repro
|
|
14
|
+
attributes:
|
|
15
|
+
label: Steps to reproduce
|
|
16
|
+
description: Minimal steps, code, or requests that trigger the issue.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: input
|
|
20
|
+
id: version
|
|
21
|
+
attributes:
|
|
22
|
+
label: Version / commit
|
|
23
|
+
validations:
|
|
24
|
+
required: false
|
|
25
|
+
- type: textarea
|
|
26
|
+
id: environment
|
|
27
|
+
attributes:
|
|
28
|
+
label: Environment
|
|
29
|
+
description: OS, Python version, vector store / embedder configuration.
|
|
30
|
+
validations:
|
|
31
|
+
required: false
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea or improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem / motivation
|
|
9
|
+
description: What problem would this solve? What's the use case?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed solution
|
|
16
|
+
description: How might it work? API sketch, configuration, behavior.
|
|
17
|
+
validations:
|
|
18
|
+
required: false
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: alternatives
|
|
21
|
+
attributes:
|
|
22
|
+
label: Alternatives considered
|
|
23
|
+
validations:
|
|
24
|
+
required: false
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this change do and why? -->
|
|
4
|
+
|
|
5
|
+
## Type of change
|
|
6
|
+
|
|
7
|
+
- [ ] Bug fix
|
|
8
|
+
- [ ] New feature
|
|
9
|
+
- [ ] Breaking change
|
|
10
|
+
- [ ] Documentation / tooling
|
|
11
|
+
|
|
12
|
+
## Checklist
|
|
13
|
+
|
|
14
|
+
- [ ] `ruff check src tests` passes
|
|
15
|
+
- [ ] `ruff format --check src tests` passes
|
|
16
|
+
- [ ] `mypy src` passes
|
|
17
|
+
- [ ] `pytest` passes
|
|
18
|
+
- [ ] Added/updated tests for the change
|
|
19
|
+
- [ ] Updated docs / CHANGELOG where relevant
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
concurrency:
|
|
9
|
+
group: ci-${{ github.ref }}
|
|
10
|
+
cancel-in-progress: true
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
python-version: ["3.11", "3.12"]
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
23
|
+
uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
|
|
27
|
+
- name: Install uv
|
|
28
|
+
uses: astral-sh/setup-uv@v3
|
|
29
|
+
|
|
30
|
+
- name: Install project
|
|
31
|
+
run: uv pip install --system -e ".[dev]"
|
|
32
|
+
|
|
33
|
+
- name: Lint (ruff)
|
|
34
|
+
run: ruff check src tests
|
|
35
|
+
|
|
36
|
+
- name: Format check (ruff)
|
|
37
|
+
run: ruff format --check src tests
|
|
38
|
+
|
|
39
|
+
- name: Type check (mypy)
|
|
40
|
+
run: mypy src
|
|
41
|
+
|
|
42
|
+
- name: Test (pytest)
|
|
43
|
+
run: pytest --cov=context_bridge --cov-report=term-missing
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
# Cut a release by bumping the version and touching `.release-trigger`.
|
|
5
|
+
push:
|
|
6
|
+
branches: ["main"]
|
|
7
|
+
paths: [".release-trigger"]
|
|
8
|
+
workflow_dispatch: {}
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
build:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.11"
|
|
21
|
+
- name: Build sdist and wheel
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade build
|
|
24
|
+
python -m build
|
|
25
|
+
- name: Check artifacts
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade twine
|
|
28
|
+
twine check dist/*
|
|
29
|
+
- uses: actions/upload-artifact@v4
|
|
30
|
+
with:
|
|
31
|
+
name: dist
|
|
32
|
+
path: dist/
|
|
33
|
+
|
|
34
|
+
github-release:
|
|
35
|
+
needs: build
|
|
36
|
+
# Only when triggered by a version tag; a manual run just builds & publishes.
|
|
37
|
+
if: github.ref_type == 'tag'
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
permissions:
|
|
40
|
+
contents: write
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/download-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
- name: Publish GitHub Release
|
|
47
|
+
uses: softprops/action-gh-release@v2
|
|
48
|
+
with:
|
|
49
|
+
files: dist/*
|
|
50
|
+
generate_release_notes: true
|
|
51
|
+
|
|
52
|
+
pypi-publish:
|
|
53
|
+
needs: build
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
# Publishes via OIDC trusted publishing. Requires a PyPI trusted publisher
|
|
56
|
+
# for this repo and a GitHub environment named 'pypi'.
|
|
57
|
+
environment: pypi
|
|
58
|
+
permissions:
|
|
59
|
+
id-token: write
|
|
60
|
+
steps:
|
|
61
|
+
- uses: actions/download-artifact@v4
|
|
62
|
+
with:
|
|
63
|
+
name: dist
|
|
64
|
+
path: dist/
|
|
65
|
+
- name: Publish to PyPI
|
|
66
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
env/
|
|
11
|
+
|
|
12
|
+
# Tooling caches
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
|
|
19
|
+
# Local state
|
|
20
|
+
*.db
|
|
21
|
+
*.sqlite3
|
|
22
|
+
.env
|
|
23
|
+
.fastembed_cache/
|
|
24
|
+
qdrant_storage/
|
|
25
|
+
|
|
26
|
+
# Editors / OS
|
|
27
|
+
.vscode/
|
|
28
|
+
.idea/
|
|
29
|
+
.DS_Store
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.6.9
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
|
|
9
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
10
|
+
rev: v5.0.0
|
|
11
|
+
hooks:
|
|
12
|
+
- id: end-of-file-fixer
|
|
13
|
+
- id: trailing-whitespace
|
|
14
|
+
- id: check-yaml
|
|
15
|
+
- id: check-toml
|
|
16
|
+
- id: check-added-large-files
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
release: v0.1.0
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-06-26
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Shared-memory core: governed write path (chunk → embed → dedup/confidence →
|
|
14
|
+
persist → log) and token-budgeted read path (hybrid search → rerank → MMR →
|
|
15
|
+
assemble).
|
|
16
|
+
- Three memory tiers: working (in-process/Redis), semantic (Qdrant dense +
|
|
17
|
+
sparse), and episodic/provenance (SQLAlchemy + Alembic).
|
|
18
|
+
- FastAPI service under a `/v1` API surface, plus sync and async SDK clients.
|
|
19
|
+
- Hybrid retrieval with client-side Reciprocal Rank Fusion, cross-encoder
|
|
20
|
+
reranking (FastEmbed) and MMR diversification.
|
|
21
|
+
- Small-to-big chunking with parent documents stored once in SQL.
|
|
22
|
+
- TTL decay: query-time filtering plus a `/maintenance/sweep` endpoint and an
|
|
23
|
+
optional background sweeper.
|
|
24
|
+
- Optional abstractive summarizer via any OpenAI-compatible endpoint, with an
|
|
25
|
+
extractive fallback.
|
|
26
|
+
- Security: opt-in API-key auth (constant-time comparison), namespace-scoped
|
|
27
|
+
keys, and a pluggable rate limiter (in-memory or Redis).
|
|
28
|
+
- Batch write and paginated listing endpoints.
|
|
29
|
+
- Observability: Prometheus metrics at `/metrics`, request-ID propagation and a
|
|
30
|
+
structured global error handler.
|
|
31
|
+
- Packaging: Apache-2.0 license, multi-stage Dockerfile, GitHub Actions CI, `py.typed`.
|
|
32
|
+
- External providers: OpenAI / Cohere embedders and the Cohere reranker.
|
|
33
|
+
- Streaming recall via Server-Sent Events (`/v1/memory/query/stream`).
|
|
34
|
+
- RBAC: per-key namespace globs with read/write permissions (`API_KEY_POLICIES`).
|
|
35
|
+
- Observability extras: Prometheus + Grafana stack, OpenTelemetry tracing.
|
|
36
|
+
- Helm chart and a runnable token-savings benchmark.
|
|
37
|
+
- Right-to-be-forgotten deletion by namespace/session, embedding-dimension
|
|
38
|
+
guard, bounded input sizes, and credential-safe CORS defaults.
|
|
39
|
+
- Tag-driven release workflow (GitHub Release + PyPI trusted publishing).
|
|
40
|
+
- Cognitive layer (opt-in, behind protocols): reflective consolidation,
|
|
41
|
+
contradiction detection & truth-maintenance, a knowledge-graph layer,
|
|
42
|
+
outcome-feedback re-ranking, and PII/secret redaction on write.
|
|
43
|
+
- Collective learning: per-namespace agent reputation profiles, task-outcome
|
|
44
|
+
credit propagation, and procedural memory (playbooks with success tracking).
|
|
45
|
+
- Salient distillation: score ephemeral conversational turns and promote only
|
|
46
|
+
the dwelled-upon ones into durable, cross-session memory
|
|
47
|
+
(`/v1/sessions/{id}/turns` + `/distill`).
|
|
48
|
+
- Temporal recall: date-aware context (`include_dates`) and `since`/`until`
|
|
49
|
+
time-window filters on query.
|
|
50
|
+
- Ontology alignment: merge surface variants of the same entity onto one
|
|
51
|
+
canonical name — automatically (`POST /v1/graph/align`) or by declaring an
|
|
52
|
+
alias (`POST /v1/graph/aliases`) — so agents converge on a shared vocabulary.
|
|
53
|
+
- Collaboration-quality score: a single composite 0-100 metric per namespace
|
|
54
|
+
(recall hit-rate, feedback positivity, conflict health) at `GET /v1/quality`,
|
|
55
|
+
so a team can watch shared memory pay off over time.
|
|
56
|
+
- Failure memory: capture a lesson from a mistake (`POST /v1/lessons`, or inline
|
|
57
|
+
with a failed `POST /v1/outcomes`) and have relevant lessons proactively raised
|
|
58
|
+
as guardrails on top of recall — so the team stops repeating the same errors.
|
|
59
|
+
Lessons rank by trigger similarity, severity and proven helpfulness, and can be
|
|
60
|
+
confirmed (`POST /v1/lessons/{id}/confirm`).
|
|
61
|
+
- Preflight briefing (`POST /v1/preflight`): before starting a task, get the
|
|
62
|
+
lessons to avoid and the playbooks that worked, in one call.
|
|
63
|
+
- Belief revision: resolving a contradiction now decays the *losing* memory's
|
|
64
|
+
confidence, and recall is confidence-weighted, so discredited memories sink and
|
|
65
|
+
repeated losses retire them — the pool changes its mind given better evidence.
|
|
66
|
+
- Auto lesson distillation (`POST /v1/lessons/distill`): cluster memories
|
|
67
|
+
implicated in failures (net-negative feedback) into auto-drafted lessons, with
|
|
68
|
+
no human in the loop.
|
|
69
|
+
- Recall explainability: every recalled chunk now carries per-signal scores
|
|
70
|
+
(match, feedback, confidence, age) and a short human-readable reason for *why*
|
|
71
|
+
it was retrieved.
|
|
72
|
+
- Memory health panel (`GET /v1/namespaces/{ns}/health`): one pulse-check of a
|
|
73
|
+
namespace — volume, trust distribution (active/demoted/retired), average
|
|
74
|
+
confidence, open conflicts, lesson and agent counts, and quality score.
|
|
75
|
+
- Auto conflict resolution (`POST /v1/conflicts/auto-resolve`): close
|
|
76
|
+
contradictions on their own when one memory's authority (trust + feedback)
|
|
77
|
+
decisively leads, leaving genuinely ambiguous cases for a human.
|
|
78
|
+
- Belief timeline / memory diff (`GET /v1/namespaces/{ns}/beliefs?query=…`):
|
|
79
|
+
trace how belief about a topic evolved over time, showing which claim fell out
|
|
80
|
+
of favour and when.
|
|
81
|
+
- Scheduled maintenance: a one-call housekeeping cycle (`POST /v1/maintenance/run`)
|
|
82
|
+
and an optional background loop (`MAINTENANCE_INTERVAL_SECONDS`) that sweeps TTL
|
|
83
|
+
and runs per-namespace auto-resolve / consolidation / lesson distillation.
|
|
84
|
+
- Event webhooks: best-effort notifications (`WEBHOOK_URLS`) for notable events —
|
|
85
|
+
`conflict.opened`, `conflict.resolved`, `lesson.created` — that never block or
|
|
86
|
+
fail a memory operation.
|
|
87
|
+
- Namespace portability: export a namespace's memories, lessons and procedures to
|
|
88
|
+
a portable, vector-free document (`GET /v1/namespaces/{ns}/export`) and restore
|
|
89
|
+
it — re-embedding on the way in — into any namespace (`POST …/import`).
|
|
90
|
+
- Cognitive-layer observability: `cb_events_total{type}`, `cb_maintenance_runs_total`
|
|
91
|
+
metrics and Grafana panels for conflicts, lessons and maintenance.
|
|
92
|
+
- Extended SDK: synchronous and async clients now cover the learning loop, failure
|
|
93
|
+
memory, preflight, truth-maintenance, graph, quality, health, belief timeline
|
|
94
|
+
and namespace import/export.
|
|
95
|
+
- Runnable offline demo (`examples/quickstart.py`) and an embedded terminal
|
|
96
|
+
render of its output in the README.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
+
orientation.
|
|
11
|
+
|
|
12
|
+
## Our standards
|
|
13
|
+
|
|
14
|
+
Examples of behavior that contributes to a positive environment:
|
|
15
|
+
|
|
16
|
+
- Demonstrating empathy and kindness toward other people
|
|
17
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
18
|
+
- Giving and gracefully accepting constructive feedback
|
|
19
|
+
- Focusing on what is best for the overall community
|
|
20
|
+
|
|
21
|
+
Examples of unacceptable behavior:
|
|
22
|
+
|
|
23
|
+
- The use of sexualized language or imagery, and unwelcome sexual attention
|
|
24
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
25
|
+
- Public or private harassment
|
|
26
|
+
- Publishing others' private information without explicit permission
|
|
27
|
+
|
|
28
|
+
## Enforcement
|
|
29
|
+
|
|
30
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
31
|
+
reported to the project maintainers. All complaints will be reviewed and
|
|
32
|
+
investigated promptly and fairly.
|
|
33
|
+
|
|
34
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
35
|
+
version 2.1.
|
|
36
|
+
|
|
37
|
+
[homepage]: https://www.contributor-covenant.org
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Contributing to Context Bridge
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving Context Bridge! This guide covers the
|
|
4
|
+
basics for getting set up and submitting changes.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# Create an environment and install with dev extras
|
|
10
|
+
uv venv && source .venv/bin/activate
|
|
11
|
+
uv pip install -e ".[dev]"
|
|
12
|
+
|
|
13
|
+
# Optional: spin up Qdrant + Postgres + Redis locally
|
|
14
|
+
docker compose up -d
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Before you open a pull request
|
|
18
|
+
|
|
19
|
+
Run the full local gate — CI runs the same checks:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
ruff check src tests # lint
|
|
23
|
+
ruff format --check src tests
|
|
24
|
+
mypy src # type-check
|
|
25
|
+
pytest # tests (hermetic; no network needed)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The default test suite is fully offline: it uses an in-process Qdrant
|
|
29
|
+
(`:memory:`), SQLite, and a deterministic hashing embedder. Tests that need a
|
|
30
|
+
downloaded model (e.g. the FastEmbed reranker smoke test) skip automatically
|
|
31
|
+
when the model is unavailable.
|
|
32
|
+
|
|
33
|
+
## Guidelines
|
|
34
|
+
|
|
35
|
+
- **Keep providers behind their protocols.** New vector stores, embedders,
|
|
36
|
+
rerankers, working-memory or summarizer backends should implement the
|
|
37
|
+
existing `Protocol` in the relevant `core/*` package — don't couple callers
|
|
38
|
+
to a concrete backend.
|
|
39
|
+
- **Add tests** for new behavior. Prefer hermetic tests; gate anything needing
|
|
40
|
+
network/models behind `pytest.importorskip` / `pytest.skip`.
|
|
41
|
+
- **Conventional commits.** Use prefixes like `feat:`, `fix:`, `docs:`,
|
|
42
|
+
`test:`, `chore:`, `refactor:`.
|
|
43
|
+
- **Type everything.** `mypy src` must pass.
|
|
44
|
+
|
|
45
|
+
## Cutting a release
|
|
46
|
+
|
|
47
|
+
Releases are tag-driven. Bump `version` in `pyproject.toml`, update
|
|
48
|
+
`CHANGELOG.md`, then:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git tag v0.1.0
|
|
52
|
+
git push origin v0.1.0
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The `Release` workflow builds the sdist/wheel and creates a GitHub Release with
|
|
56
|
+
generated notes, then publishes to PyPI via OIDC **trusted publishing**. One-time
|
|
57
|
+
setup:
|
|
58
|
+
|
|
59
|
+
1. On PyPI, add a **trusted publisher** for this repo (workflow `release.yml`,
|
|
60
|
+
environment `pypi`) — no token needed.
|
|
61
|
+
2. On GitHub, create an **environment** named `pypi` (Settings → Environments).
|
|
62
|
+
|
|
63
|
+
Then tagging a version cuts the release and publishes automatically.
|
|
64
|
+
|
|
65
|
+
## Reporting bugs / requesting features
|
|
66
|
+
|
|
67
|
+
Open an issue using the provided templates. For security issues, please follow
|
|
68
|
+
[SECURITY.md](SECURITY.md) instead of filing a public issue.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
|
|
3
|
+
# --- builder: install dependencies into a venv ---
|
|
4
|
+
FROM python:3.11-slim AS builder
|
|
5
|
+
|
|
6
|
+
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
|
7
|
+
PIP_NO_CACHE_DIR=1 \
|
|
8
|
+
PYTHONDONTWRITEBYTECODE=1
|
|
9
|
+
|
|
10
|
+
WORKDIR /app
|
|
11
|
+
|
|
12
|
+
RUN python -m venv /opt/venv
|
|
13
|
+
ENV PATH="/opt/venv/bin:$PATH"
|
|
14
|
+
|
|
15
|
+
# Install dependencies first for better layer caching.
|
|
16
|
+
COPY pyproject.toml README.md ./
|
|
17
|
+
COPY src ./src
|
|
18
|
+
RUN pip install ".[fastembed,redis,postgres]"
|
|
19
|
+
|
|
20
|
+
# --- runtime: minimal image ---
|
|
21
|
+
FROM python:3.11-slim AS runtime
|
|
22
|
+
|
|
23
|
+
ENV PATH="/opt/venv/bin:$PATH" \
|
|
24
|
+
PYTHONUNBUFFERED=1 \
|
|
25
|
+
PYTHONDONTWRITEBYTECODE=1 \
|
|
26
|
+
API_HOST=0.0.0.0 \
|
|
27
|
+
API_PORT=8000
|
|
28
|
+
|
|
29
|
+
# Run as a non-root user.
|
|
30
|
+
RUN useradd --create-home --uid 10001 appuser
|
|
31
|
+
WORKDIR /app
|
|
32
|
+
|
|
33
|
+
COPY --from=builder /opt/venv /opt/venv
|
|
34
|
+
COPY --from=builder /app/src /app/src
|
|
35
|
+
COPY pyproject.toml README.md ./
|
|
36
|
+
|
|
37
|
+
USER appuser
|
|
38
|
+
EXPOSE 8000
|
|
39
|
+
|
|
40
|
+
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
|
|
41
|
+
CMD python -c "import urllib.request,os;urllib.request.urlopen(f'http://127.0.0.1:{os.environ.get(\"API_PORT\",\"8000\")}/health').read()" || exit 1
|
|
42
|
+
|
|
43
|
+
CMD ["python", "-m", "context_bridge"]
|