context-engineering-core 0.12.1__tar.gz → 0.15.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.
Files changed (99) hide show
  1. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/CHANGELOG.md +58 -1
  2. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/PKG-INFO +33 -7
  3. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/README.md +27 -6
  4. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/pyproject.toml +4 -2
  5. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/__init__.py +1 -1
  6. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/cli.py +21 -1
  7. context_engineering_core-0.15.0/src/context_engine/embedding_data/LICENSE +33 -0
  8. context_engineering_core-0.15.0/src/context_engine/embedding_data/potion-base-8M-int8.npz +0 -0
  9. context_engineering_core-0.15.0/src/context_engine/embedding_data/potion-base-8M-vocab.txt +29528 -0
  10. context_engineering_core-0.15.0/src/context_engine/embeddings.py +249 -0
  11. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/data/freeze.json +2 -2
  12. context_engineering_core-0.15.0/src/context_engine/evaluation/data/paraphrases.json +38 -0
  13. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/grading.py +30 -0
  14. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/harness.py +1 -0
  15. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/strategies.py +134 -19
  16. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/layers/retrieve.py +28 -6
  17. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/mcp_server.py +10 -4
  18. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/pipeline.py +19 -1
  19. context_engineering_core-0.15.0/src/context_engine/wordpiece.py +114 -0
  20. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/.gitignore +0 -0
  21. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/LICENSE +0 -0
  22. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/evidence_answer_policy.py +0 -0
  23. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/incident-demo.json +0 -0
  24. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/inspection-input.json +0 -0
  25. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/rolling_summary.py +0 -0
  26. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/sdk_quickstart.py +0 -0
  27. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/service-config.example.json +0 -0
  28. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/structured_answers.py +0 -0
  29. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/examples/validated_answer.py +0 -0
  30. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/__main__.py +0 -0
  31. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/_sqlite.py +0 -0
  32. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/_windows_security.py +0 -0
  33. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/_windows_storage.py +0 -0
  34. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/adapters.py +0 -0
  35. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/answers.py +0 -0
  36. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/budget.py +0 -0
  37. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/config.py +0 -0
  38. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/context.py +0 -0
  39. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/demo.py +0 -0
  40. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/errors.py +0 -0
  41. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/__init__.py +0 -0
  42. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/commands.py +0 -0
  43. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/corpus.py +0 -0
  44. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/data/ground_truth.json +0 -0
  45. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/data/pin_retention.json +0 -0
  46. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/data/protocol.json +0 -0
  47. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/data/scenario.json +0 -0
  48. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/data/summary_fixture.json +0 -0
  49. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/execution.py +0 -0
  50. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/fixtures.py +0 -0
  51. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/__init__.py +0 -0
  52. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/__main__.py +0 -0
  53. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/data/ground_truth.json +0 -0
  54. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/data/manifest.json +0 -0
  55. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/data/protocol.json +0 -0
  56. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/data/scenarios.json +0 -0
  57. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/data/scoring_manifest.json +0 -0
  58. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/data/scoring_protocol.json +0 -0
  59. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/heldout/scoring.py +0 -0
  60. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/protocol.py +0 -0
  61. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/reporting.py +0 -0
  62. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/results.py +0 -0
  63. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/evaluation/run_commands.py +0 -0
  64. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/inspection.py +0 -0
  65. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/layers/__init__.py +0 -0
  66. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/layers/cap.py +0 -0
  67. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/layers/common.py +0 -0
  68. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/layers/pin.py +0 -0
  69. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/layers/summarize.py +0 -0
  70. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/layers/window.py +0 -0
  71. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/memory/__init__.py +0 -0
  72. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/memory/codec.py +0 -0
  73. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/memory/demo.py +0 -0
  74. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/memory/store.py +0 -0
  75. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/models.py +0 -0
  76. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/__init__.py +0 -0
  77. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/client.py +0 -0
  78. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/commands.py +0 -0
  79. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/contracts.py +0 -0
  80. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/credentials.py +0 -0
  81. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/memory.py +0 -0
  82. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/store.py +0 -0
  83. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/transport.py +0 -0
  84. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/providers/windows_credentials.py +0 -0
  85. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/py.typed +0 -0
  86. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/__init__.py +0 -0
  87. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/__main__.py +0 -0
  88. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/app.py +0 -0
  89. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/auth.py +0 -0
  90. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/client.py +0 -0
  91. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/control.py +0 -0
  92. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/demo.py +0 -0
  93. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/integrations.py +0 -0
  94. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/schemas.py +0 -0
  95. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/worker.py +0 -0
  96. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/service/workers.py +0 -0
  97. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/summaries.py +0 -0
  98. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/tokens.py +0 -0
  99. {context_engineering_core-0.12.1 → context_engineering_core-0.15.0}/src/context_engine/work.py +0 -0
@@ -3,7 +3,64 @@
3
3
  Earlier versions (0.1.0–0.9.6) are documented in `docs/C01_REPORT.md` through
4
4
  `docs/C10_STORAGE_ACL_REPORT.md` and preserved as wheels under `archives/`.
5
5
 
6
- ## 0.12.1 — 2026-10-31 (unreleased)
6
+ ## 0.15.0 — 2026-10-31 (unreleased)
7
+
8
+ ### Changed (behavior)
9
+ - Hybrid retrieval is the default (`assemble_context(embedder="builtin")`): the
10
+ bundled potion-base-8M model (8-bit vectors, ~7 MB in the package; MIT notice in
11
+ `embedding_data/LICENSE`) with a pure-Python WordPiece tokenizer. No download,
12
+ network or new dependency. `embedder=None` gives the pre-0.15.0 keyword-only path.
13
+ - Default `semantic_weight` 0.7 → 0.5: a needle-in-filler check showed 0.7 losing
14
+ exact keyword matches (22/31 vs 31/31); 0.5 is equal or better on every set.
15
+ - `strategy-eval` includes the hybrid strategies by default (`--no-semantic` to
16
+ skip; `--semantic` removed). `context-engine-mcp` is hybrid by default
17
+ (`--no-semantic`; `--semantic` removed).
18
+ - The frozen benchmark harness pins keyword-only retrieval.
19
+
20
+ ### Added
21
+ - `BuiltinEmbedder`, `default_embedder()`, `context_engine.wordpiece`.
22
+ - Lenient grading v2 (`answer_correct_lenient`, `GRADERS`) beside frozen strict v1;
23
+ `scripts/regrade_live.py` writes `grading.json` for both live runs.
24
+
25
+ ### Unchanged
26
+ - 0.14.0 wheel/freeze archived in `archives/c15-default-semantic-0150/`.
27
+
28
+ ## 0.14.0 — 2026-10-31 (PyPI)
29
+
30
+ ### Added
31
+ - Optional hybrid retrieval: `assemble_context(..., embedder=, semantic_weight=0.7)`
32
+ (also via `MemoryStore.assemble`) ranks chunks by 0.7 x meaning + 0.3 x keyword
33
+ score. `context_engine.embeddings`: `Embedder` protocol, `Model2VecEmbedder`
34
+ (default model pinned: `minishlab/potion-base-8M@bf8b0566`, extra `[semantic]`),
35
+ `FastEmbedEmbedder` (extra `[fastembed]`), `FunctionEmbedder`. Bounded vector cache.
36
+ - `strategy-eval --semantic` (adds `retrieval_semantic`, `combined_semantic`) and
37
+ `context-engine-mcp --semantic`.
38
+ - Reworded questions: default retention 3/31 → 21/31 with the embedder; original
39
+ questions stay 31/31. Bake-off evidence in `output/embedding-bakeoff-001/`.
40
+
41
+ ### Changed
42
+ - `numpy` is now a declared dependency (it was already installed via `rank-bm25`).
43
+ - Missing optional extras give an install hint instead of a traceback.
44
+
45
+ ### Unchanged
46
+ - Without an embedder, all 310 strategy-benchmark assemblies are byte-identical to
47
+ 0.13.0 (archived in `archives/c14-semantic-0140/`).
48
+
49
+ ## 0.13.0 — 2026-10-31 (unreleased)
50
+
51
+ ### Added
52
+ - Reworded-question stress test: `strategy-eval --questions paraphrased` and
53
+ `compare_strategies(..., questions="paraphrased")`. 31 questions share no content
54
+ word (or 4-letter start of a 5+ letter word) with their evidence, enforced by
55
+ `paraphrase_overlaps`. Result: default retention falls from 31/31 to 3/31 at 900
56
+ and 3000 tokens (retrieval alone: 6/31 and 7/31). README updated.
57
+ - `assemble_strategy(..., question=...)` to assemble a strategy for any question.
58
+
59
+ ### Unchanged
60
+ - Engine behavior and defaults. 0.12.1 wheel/freeze archived in
61
+ `archives/c13-paraphrase-0130/`.
62
+
63
+ ## 0.12.1 — 2026-10-31 (PyPI)
7
64
 
8
65
  ### Changed (performance only; output identical)
9
66
  - Budget fit checks compute only the request's estimated token count
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: context-engineering-core
3
- Version: 0.12.1
3
+ Version: 0.15.0
4
4
  Summary: Provider-independent context layers, source contracts, and token budget accounting
5
5
  Project-URL: Homepage, https://github.com/Nandu1729/Context-Engine
6
6
  Project-URL: Repository, https://github.com/Nandu1729/Context-Engine
@@ -18,15 +18,20 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Classifier: Typing :: Typed
20
20
  Requires-Python: >=3.12
21
+ Requires-Dist: numpy>=1.26
21
22
  Requires-Dist: pywin32==311; sys_platform == 'win32'
22
23
  Requires-Dist: rank-bm25<0.3,>=0.2.2
23
24
  Requires-Dist: tiktoken<0.15,>=0.14
25
+ Provides-Extra: fastembed
26
+ Requires-Dist: fastembed<0.10,>=0.9; extra == 'fastembed'
24
27
  Provides-Extra: langchain
25
28
  Requires-Dist: langchain-core<2,>=1.0; extra == 'langchain'
26
29
  Provides-Extra: provider
27
30
  Requires-Dist: httpx<0.29,>=0.28; extra == 'provider'
28
31
  Provides-Extra: reports
29
32
  Requires-Dist: matplotlib<3.12,>=3.11; extra == 'reports'
33
+ Provides-Extra: semantic
34
+ Requires-Dist: model2vec<0.11,>=0.10; extra == 'semantic'
30
35
  Provides-Extra: service
31
36
  Requires-Dist: fastapi<0.136,>=0.135; extra == 'service'
32
37
  Requires-Dist: httpx<0.29,>=0.28; extra == 'service'
@@ -45,7 +50,7 @@ that fits the budget. Those messages keep the recent turns, the facts you pinned
45
50
  and the older evidence that matches the question. It never calls a model by
46
51
  itself, so you send the messages to any provider you like.
47
52
 
48
- > **Status: alpha (0.12.0).** Good for developers to try locally. It is not yet
53
+ > **Status: alpha (0.15.0).** Good for developers to try locally. It is not yet
49
54
  > proven on real-world data, and there is no hosted service. See
50
55
  > [What is not proven yet](#what-is-not-proven-yet).
51
56
 
@@ -106,6 +111,21 @@ chat_model.invoke(langchain_messages(result)) # pip install 'context-engineerin
106
111
  history = turns_from_openai(existing_openai_messages, scope) # reuse a chat history you already have
107
112
  ```
108
113
 
114
+ ### Finds meaning, not just matching words
115
+
116
+ Retrieval combines keyword search with a small embedding model bundled in the
117
+ package, so "retailer" finds "merchant". It runs locally with numpy: no download,
118
+ no network, no extra dependency (the package is ~7 MB because of the model).
119
+ Ranking is 0.5 x meaning score + 0.5 x keyword score.
120
+
121
+ ```python
122
+ result = assemble_context(..., embedder=None) # keyword-only, as before 0.15.0
123
+ from context_engine.embeddings import FastEmbedEmbedder, FunctionEmbedder, Model2VecEmbedder
124
+ result = assemble_context(..., embedder=FastEmbedEmbedder()) # more accurate, slower (extra [fastembed])
125
+ ```
126
+
127
+ `FunctionEmbedder` wraps your own embedding function or API.
128
+
109
129
  ### Use it from an MCP client
110
130
 
111
131
  `context-engine-mcp --data-dir ./context-memory` runs a local MCP server (stdio) with
@@ -154,11 +174,17 @@ These are enforced in code and covered by about 1,400 tests:
154
174
  - **Answer quality.** Tests measure whether the needed facts *reach* the model's
155
175
  context, not whether the model then answers correctly. On the built-in
156
176
  benchmark, the default settings keep 31 of 31 planted facts at 900 and 3000
157
- tokens. But that benchmark is one synthetic conversation written alongside
158
- the engine.
159
- - **Real-world data.** There are no results yet on real user conversations or
160
- on questions phrased differently from the source text. Retrieval is
161
- keyword-based (BM25), so heavily reworded questions may miss evidence.
177
+ tokens, and a live model run answered 31 of 31 correctly at 900 tokens. But
178
+ that benchmark is one synthetic conversation written alongside the engine.
179
+ - **Reworded questions.** When we reword the 31 benchmark questions so they share
180
+ no words with the stored facts, keyword-only retrieval keeps 3 of 31 facts; the
181
+ default hybrid retrieval keeps 21 of 31 (retrieval alone: 24–25 of 31), with no
182
+ loss on the original questions. In a live model run on the reworded questions,
183
+ keyword-only answered 3 of 31 correctly and hybrid 18 of 31 (21 of 31 with
184
+ lenient grading, which ignores trailing punctuation and dash characters). A fact
185
+ buried in a long, repetitive message and asked with different words is still
186
+ hard (12 of 31). Run the offline test: `context-engine strategy-eval --questions paraphrased`.
187
+ - **Real-world data.** There are no results yet on real user conversations.
162
188
  - **Exact provider token counts.** Budgets use a local tokenizer estimate.
163
189
  Providers may count differently. On small requests, provider counts were up
164
190
  to 1.78× the local estimate in past tests, so leave headroom or calibrate.
@@ -9,7 +9,7 @@ that fits the budget. Those messages keep the recent turns, the facts you pinned
9
9
  and the older evidence that matches the question. It never calls a model by
10
10
  itself, so you send the messages to any provider you like.
11
11
 
12
- > **Status: alpha (0.12.0).** Good for developers to try locally. It is not yet
12
+ > **Status: alpha (0.15.0).** Good for developers to try locally. It is not yet
13
13
  > proven on real-world data, and there is no hosted service. See
14
14
  > [What is not proven yet](#what-is-not-proven-yet).
15
15
 
@@ -70,6 +70,21 @@ chat_model.invoke(langchain_messages(result)) # pip install 'context-engineerin
70
70
  history = turns_from_openai(existing_openai_messages, scope) # reuse a chat history you already have
71
71
  ```
72
72
 
73
+ ### Finds meaning, not just matching words
74
+
75
+ Retrieval combines keyword search with a small embedding model bundled in the
76
+ package, so "retailer" finds "merchant". It runs locally with numpy: no download,
77
+ no network, no extra dependency (the package is ~7 MB because of the model).
78
+ Ranking is 0.5 x meaning score + 0.5 x keyword score.
79
+
80
+ ```python
81
+ result = assemble_context(..., embedder=None) # keyword-only, as before 0.15.0
82
+ from context_engine.embeddings import FastEmbedEmbedder, FunctionEmbedder, Model2VecEmbedder
83
+ result = assemble_context(..., embedder=FastEmbedEmbedder()) # more accurate, slower (extra [fastembed])
84
+ ```
85
+
86
+ `FunctionEmbedder` wraps your own embedding function or API.
87
+
73
88
  ### Use it from an MCP client
74
89
 
75
90
  `context-engine-mcp --data-dir ./context-memory` runs a local MCP server (stdio) with
@@ -118,11 +133,17 @@ These are enforced in code and covered by about 1,400 tests:
118
133
  - **Answer quality.** Tests measure whether the needed facts *reach* the model's
119
134
  context, not whether the model then answers correctly. On the built-in
120
135
  benchmark, the default settings keep 31 of 31 planted facts at 900 and 3000
121
- tokens. But that benchmark is one synthetic conversation written alongside
122
- the engine.
123
- - **Real-world data.** There are no results yet on real user conversations or
124
- on questions phrased differently from the source text. Retrieval is
125
- keyword-based (BM25), so heavily reworded questions may miss evidence.
136
+ tokens, and a live model run answered 31 of 31 correctly at 900 tokens. But
137
+ that benchmark is one synthetic conversation written alongside the engine.
138
+ - **Reworded questions.** When we reword the 31 benchmark questions so they share
139
+ no words with the stored facts, keyword-only retrieval keeps 3 of 31 facts; the
140
+ default hybrid retrieval keeps 21 of 31 (retrieval alone: 24–25 of 31), with no
141
+ loss on the original questions. In a live model run on the reworded questions,
142
+ keyword-only answered 3 of 31 correctly and hybrid 18 of 31 (21 of 31 with
143
+ lenient grading, which ignores trailing punctuation and dash characters). A fact
144
+ buried in a long, repetitive message and asked with different words is still
145
+ hard (12 of 31). Run the offline test: `context-engine strategy-eval --questions paraphrased`.
146
+ - **Real-world data.** There are no results yet on real user conversations.
126
147
  - **Exact provider token counts.** Budgets use a local tokenizer estimate.
127
148
  Providers may count differently. On small requests, provider counts were up
128
149
  to 1.78× the local estimate in past tests, so leave headroom or calibrate.
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "context-engineering-core"
7
- version = "0.12.1"
7
+ version = "0.15.0"
8
8
  description = "Provider-independent context layers, source contracts, and token budget accounting"
9
9
  readme = "README.md"
10
10
  license = "Apache-2.0"
@@ -21,11 +21,13 @@ classifiers = [
21
21
  "Topic :: Software Development :: Libraries :: Python Modules",
22
22
  "Typing :: Typed",
23
23
  ]
24
- dependencies = ["tiktoken>=0.14,<0.15", "rank-bm25>=0.2.2,<0.3", "pywin32==311; sys_platform == 'win32'"]
24
+ dependencies = ["tiktoken>=0.14,<0.15", "rank-bm25>=0.2.2,<0.3", "numpy>=1.26", "pywin32==311; sys_platform == 'win32'"]
25
25
 
26
26
  [project.optional-dependencies]
27
27
  provider = ["httpx>=0.28,<0.29"]
28
28
  langchain = ["langchain-core>=1.0,<2"]
29
+ semantic = ["model2vec>=0.10,<0.11"]
30
+ fastembed = ["fastembed>=0.9,<0.10"]
29
31
  reports = ["matplotlib>=3.11,<3.12"]
30
32
  service = ["fastapi>=0.135,<0.136", "uvicorn>=0.41,<0.42", "PyJWT[crypto]>=2.12,<3", "httpx>=0.28,<0.29"]
31
33
 
@@ -1,6 +1,6 @@
1
1
  """Core contracts. Importing this package performs no configuration or network I/O."""
2
2
 
3
- __version__ = "0.12.1"
3
+ __version__ = "0.15.0"
4
4
 
5
5
 
6
6
  def __getattr__(name):
@@ -81,6 +81,17 @@ def main(argv: list[str] | None = None) -> int:
81
81
  "--budget", type=int, action="append", help="Input allowance; repeatable"
82
82
  )
83
83
  strategies.add_argument("--probes", action="store_true", help="Include per-fact results")
84
+ strategies.add_argument(
85
+ "--questions",
86
+ choices=("original", "paraphrased"),
87
+ default="original",
88
+ help="paraphrased: reworded questions with no shared words (lexical stress test)",
89
+ )
90
+ strategies.add_argument(
91
+ "--no-semantic",
92
+ action="store_true",
93
+ help="Skip the hybrid strategies (retrieval_semantic, combined_semantic)",
94
+ )
84
95
  strategies.add_argument("--data-dir", type=Path)
85
96
  strategies.add_argument("--output", type=Path, help="Save JSON to a new file; never overwrite")
86
97
  planned = commands.add_parser(
@@ -136,7 +147,13 @@ def main(argv: list[str] | None = None) -> int:
136
147
  budgets = None if args.budget is None else tuple(args.budget)
137
148
  if budgets is not None and any(b <= 0 for b in budgets):
138
149
  raise ContextEngineError("Budgets must be positive integers")
139
- result = compare_strategies(bundle, budgets, include_probes=args.probes)
150
+ result = compare_strategies(
151
+ bundle,
152
+ budgets,
153
+ include_probes=args.probes,
154
+ questions=args.questions,
155
+ embedder=None if args.no_semantic else "builtin",
156
+ )
140
157
  if args.output is not None:
141
158
  save_inspection(args.output, result)
142
159
  print(json.dumps(result, indent=2, ensure_ascii=False))
@@ -216,6 +233,9 @@ def main(argv: list[str] | None = None) -> int:
216
233
  except ContextEngineError as error:
217
234
  print(json.dumps(error.to_dict()), file=sys.stderr)
218
235
  return 1
236
+ except ImportError as error: # An optional extra (e.g. [semantic]) is missing.
237
+ print(json.dumps({"code": "missing_extra", "message": str(error)}), file=sys.stderr)
238
+ return 2
219
239
 
220
240
 
221
241
  if __name__ == "__main__":
@@ -0,0 +1,33 @@
1
+ Bundled embedding model data
2
+ ============================
3
+
4
+ potion-base-8M-int8.npz and potion-base-8M-vocab.txt are derived from the
5
+ Model2Vec model "minishlab/potion-base-8M" (revision
6
+ bf8b056651a2c21b8d2565580b8569da283cab23), https://huggingface.co/minishlab/potion-base-8M,
7
+ licensed under the MIT License. Its vocabulary comes from BAAI/bge-base-en-v1.5
8
+ (MIT License). The vectors were quantized to 8-bit integers with one float32
9
+ scale per token by the Context Engine project; no other changes.
10
+
11
+ MIT License
12
+
13
+ Copyright (c) 2024 Thomas van Dongen
14
+ (copyright line as in the MIT license of the model2vec project; the model card
15
+ of minishlab/potion-base-8M declares "license: mit")
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ of this software and associated documentation files (the "Software"), to deal
19
+ in the Software without restriction, including without limitation the rights
20
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ copies of the Software, and to permit persons to whom the Software is
22
+ furnished to do so, subject to the following conditions:
23
+
24
+ The above copyright notice and this permission notice shall be included in all
25
+ copies or substantial portions of the Software.
26
+
27
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
+ SOFTWARE.