quasar-context 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sebastian Sabo
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,202 @@
1
+ Metadata-Version: 2.4
2
+ Name: quasar-context
3
+ Version: 0.1.0
4
+ Summary: Faithful context optimization for RAG apps — compress without corrupting critical data
5
+ Author: Sebastian Sabo
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/sebastiansabo/quasar
8
+ Project-URL: Issues, https://github.com/sebastiansabo/quasar/issues
9
+ Keywords: rag,llm,context,compression,prompt,embeddings
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: sentence-transformers>=2.2.0
19
+ Requires-Dist: tiktoken>=0.5.0
20
+ Requires-Dist: numpy>=1.21.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=7.0; extra == "dev"
23
+ Requires-Dist: pytest-cov; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # Quasar
27
+
28
+ **Faithful context optimization for RAG apps.**
29
+
30
+ Compress retrieved context before your LLM call — without silently corrupting the
31
+ values that matter. Prices, IBANs, dates, invoice numbers, legal references and
32
+ IDs are preserved **verbatim** when the budget allows. When it doesn't, Quasar
33
+ **tells you** instead of quietly dropping them.
34
+
35
+ ```python
36
+ from quasar import ContextOptimizer
37
+
38
+ opt = ContextOptimizer()
39
+ result = opt.optimize(query, retrieved_chunks, target_tokens=500)
40
+
41
+ llm_answer(query, result.context) # feed the compressed context
42
+ print(result.report.summary())
43
+ # [Quasar] 63% smaller (1284->475 tok, ~$0.0024 saved) | critical 7/7 OK
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Why this exists
49
+
50
+ Every context compressor optimizes for one thing: fewer tokens. None of them tell
51
+ you what they destroyed on the way.
52
+
53
+ If your RAG app retrieves an invoice and the compressor drops or mangles
54
+ `€47,350.00`, your LLM confidently answers with the wrong number and **you never
55
+ find out**. That's fine for a chatbot. It is not fine for finance, legal,
56
+ medical, compliance, or code.
57
+
58
+ Quasar makes one guarantee no other compressor makes:
59
+
60
+ > **It never silently corrupts your critical data.**
61
+ > Critical values survive verbatim, or you get an explicit warning.
62
+
63
+ ---
64
+
65
+ ## What it does
66
+
67
+ 1. **Detects critical spans** — currency, IBANs, dates, VINs, long IDs, legal
68
+ references, contract codes — by pattern.
69
+ 2. **Reserves them verbatim.** Critical sentences claim budget first and are
70
+ never rewritten. (Token-deletion compressors *rewrite* text — that's how they
71
+ corrupt exact values.)
72
+ 3. **Fills the remaining budget by relevance**, using embedding similarity to the
73
+ query. Filler is dropped.
74
+ 4. **Dedupes** repeated sentences so budget isn't wasted on copies.
75
+ 5. **Audits and reports.** Every call returns tokens saved, cost saved, and a
76
+ faithfulness status — with warnings naming any critical value it couldn't fit.
77
+
78
+ ---
79
+
80
+ ## Honest benchmarks
81
+
82
+ Measured on LongBench (narrativeqa / qasper / hotpotqa, N=30 per task), real LLM
83
+ judge, token-F1 scoring.
84
+
85
+ **Where Quasar wins:**
86
+
87
+ | Matchup | Result |
88
+ |---|---|
89
+ | vs **truncation** | **9–0** — wins at every task and budget |
90
+ | vs **LLMLingua** | **6–0** on accuracy, **8–13× faster** to compress |
91
+ | Long contexts | Handles 17k+ word documents LLMLingua **cannot process at all** |
92
+
93
+ LLMLingua runs a neural model to compress. Quasar runs embeddings. Same or better
94
+ accuracy, a fraction of the compute.
95
+
96
+ **Where Quasar does not win — stated plainly:**
97
+
98
+ Against a **pure top-k embedding filter** (e.g. LangChain's `EmbeddingsFilter`),
99
+ Quasar goes **3–6** on raw QA accuracy. On pure question-answering, simple
100
+ relevance ranking is competitive or better.
101
+
102
+ **So Quasar is not the accuracy leader on QA, and doesn't claim to be.** Its value
103
+ is the axis those benchmarks don't measure: *faithfulness*. A top-k filter has no
104
+ concept of critical data — it drops a low-relevance sentence containing your
105
+ invoice number without hesitation, and never tells you. Quasar reserves it, and
106
+ warns when it can't.
107
+
108
+ **Use Quasar when correctness of exact values matters more than the last 2% of
109
+ retrieval F1.** If you're building a general chatbot and only care about QA
110
+ accuracy, use a top-k filter — it's simpler and we'll say so.
111
+
112
+ ---
113
+
114
+ ## Install
115
+
116
+ ```bash
117
+ pip install quasar-context
118
+ ```
119
+
120
+ ## Usage
121
+
122
+ ### Basic
123
+
124
+ ```python
125
+ from quasar import ContextOptimizer
126
+
127
+ opt = ContextOptimizer() # loads the embedding model once
128
+ result = opt.optimize(
129
+ query="What is the total due and the deadline?",
130
+ context=retrieved_chunks, # str or list[str]
131
+ target_tokens=500,
132
+ )
133
+
134
+ result.context # compressed text for your LLM
135
+ result.report.tokens_saved # int
136
+ result.report.faithful # bool — did all critical values survive?
137
+ result.report.warnings # list[str] — what got dropped and why
138
+ ```
139
+
140
+ ### Guarding a production call
141
+
142
+ ```python
143
+ result = opt.optimize(query, chunks, target_tokens=500)
144
+
145
+ if not result.report.faithful:
146
+ # budget too tight to hold every critical value — your call:
147
+ logger.warning("Quasar: %s", result.report.warnings)
148
+ result = opt.optimize(query, chunks, target_tokens=1000) # give it room
149
+
150
+ answer = llm(query, result.context)
151
+ ```
152
+
153
+ ### Configuration
154
+
155
+ ```python
156
+ from quasar import ContextOptimizer, OptimizerConfig
157
+
158
+ opt = ContextOptimizer(OptimizerConfig(
159
+ cost_per_1k_tokens=0.003, # your model's price, for the savings report
160
+ preserve_critical=True, # the faithfulness behavior (default on)
161
+ min_relevance=0.05, # drop sentences below this query relevance
162
+ model_name="all-MiniLM-L6-v2",
163
+ ))
164
+ ```
165
+
166
+ ### Custom critical patterns
167
+
168
+ Your domain has its own critical formats. Add them:
169
+
170
+ ```python
171
+ from quasar import core
172
+ core._CRITICAL_PATTERNS.append((r"\bCASE-\d{6}\b", "case_id"))
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Performance
178
+
179
+ - **~10–100 ms per call** after warm-up (embedding + greedy selection).
180
+ - **First call loads the model** (~30–60s, one time). Warm it at startup:
181
+ ```python
182
+ opt = ContextOptimizer()
183
+ opt.optimize("warmup", "warmup text.", target_tokens=50)
184
+ ```
185
+ - **8–13× faster than LLMLingua**, which runs a full neural model to compress.
186
+
187
+ ---
188
+
189
+ ## What Quasar is not
190
+
191
+ - **Not the best compressor by ratio.** Token-deletion methods compress harder.
192
+ They also rewrite your text.
193
+ - **Not an accuracy leader on pure QA.** A top-k filter matches or beats it there.
194
+ - **Not a guarantee against physics.** If your critical content is larger than
195
+ your token budget, it cannot all fit. Quasar preserves what it can *and tells
196
+ you what it couldn't* — that's the honest contract.
197
+
198
+ ---
199
+
200
+ ## License
201
+
202
+ MIT.
@@ -0,0 +1,177 @@
1
+ # Quasar
2
+
3
+ **Faithful context optimization for RAG apps.**
4
+
5
+ Compress retrieved context before your LLM call — without silently corrupting the
6
+ values that matter. Prices, IBANs, dates, invoice numbers, legal references and
7
+ IDs are preserved **verbatim** when the budget allows. When it doesn't, Quasar
8
+ **tells you** instead of quietly dropping them.
9
+
10
+ ```python
11
+ from quasar import ContextOptimizer
12
+
13
+ opt = ContextOptimizer()
14
+ result = opt.optimize(query, retrieved_chunks, target_tokens=500)
15
+
16
+ llm_answer(query, result.context) # feed the compressed context
17
+ print(result.report.summary())
18
+ # [Quasar] 63% smaller (1284->475 tok, ~$0.0024 saved) | critical 7/7 OK
19
+ ```
20
+
21
+ ---
22
+
23
+ ## Why this exists
24
+
25
+ Every context compressor optimizes for one thing: fewer tokens. None of them tell
26
+ you what they destroyed on the way.
27
+
28
+ If your RAG app retrieves an invoice and the compressor drops or mangles
29
+ `€47,350.00`, your LLM confidently answers with the wrong number and **you never
30
+ find out**. That's fine for a chatbot. It is not fine for finance, legal,
31
+ medical, compliance, or code.
32
+
33
+ Quasar makes one guarantee no other compressor makes:
34
+
35
+ > **It never silently corrupts your critical data.**
36
+ > Critical values survive verbatim, or you get an explicit warning.
37
+
38
+ ---
39
+
40
+ ## What it does
41
+
42
+ 1. **Detects critical spans** — currency, IBANs, dates, VINs, long IDs, legal
43
+ references, contract codes — by pattern.
44
+ 2. **Reserves them verbatim.** Critical sentences claim budget first and are
45
+ never rewritten. (Token-deletion compressors *rewrite* text — that's how they
46
+ corrupt exact values.)
47
+ 3. **Fills the remaining budget by relevance**, using embedding similarity to the
48
+ query. Filler is dropped.
49
+ 4. **Dedupes** repeated sentences so budget isn't wasted on copies.
50
+ 5. **Audits and reports.** Every call returns tokens saved, cost saved, and a
51
+ faithfulness status — with warnings naming any critical value it couldn't fit.
52
+
53
+ ---
54
+
55
+ ## Honest benchmarks
56
+
57
+ Measured on LongBench (narrativeqa / qasper / hotpotqa, N=30 per task), real LLM
58
+ judge, token-F1 scoring.
59
+
60
+ **Where Quasar wins:**
61
+
62
+ | Matchup | Result |
63
+ |---|---|
64
+ | vs **truncation** | **9–0** — wins at every task and budget |
65
+ | vs **LLMLingua** | **6–0** on accuracy, **8–13× faster** to compress |
66
+ | Long contexts | Handles 17k+ word documents LLMLingua **cannot process at all** |
67
+
68
+ LLMLingua runs a neural model to compress. Quasar runs embeddings. Same or better
69
+ accuracy, a fraction of the compute.
70
+
71
+ **Where Quasar does not win — stated plainly:**
72
+
73
+ Against a **pure top-k embedding filter** (e.g. LangChain's `EmbeddingsFilter`),
74
+ Quasar goes **3–6** on raw QA accuracy. On pure question-answering, simple
75
+ relevance ranking is competitive or better.
76
+
77
+ **So Quasar is not the accuracy leader on QA, and doesn't claim to be.** Its value
78
+ is the axis those benchmarks don't measure: *faithfulness*. A top-k filter has no
79
+ concept of critical data — it drops a low-relevance sentence containing your
80
+ invoice number without hesitation, and never tells you. Quasar reserves it, and
81
+ warns when it can't.
82
+
83
+ **Use Quasar when correctness of exact values matters more than the last 2% of
84
+ retrieval F1.** If you're building a general chatbot and only care about QA
85
+ accuracy, use a top-k filter — it's simpler and we'll say so.
86
+
87
+ ---
88
+
89
+ ## Install
90
+
91
+ ```bash
92
+ pip install quasar-context
93
+ ```
94
+
95
+ ## Usage
96
+
97
+ ### Basic
98
+
99
+ ```python
100
+ from quasar import ContextOptimizer
101
+
102
+ opt = ContextOptimizer() # loads the embedding model once
103
+ result = opt.optimize(
104
+ query="What is the total due and the deadline?",
105
+ context=retrieved_chunks, # str or list[str]
106
+ target_tokens=500,
107
+ )
108
+
109
+ result.context # compressed text for your LLM
110
+ result.report.tokens_saved # int
111
+ result.report.faithful # bool — did all critical values survive?
112
+ result.report.warnings # list[str] — what got dropped and why
113
+ ```
114
+
115
+ ### Guarding a production call
116
+
117
+ ```python
118
+ result = opt.optimize(query, chunks, target_tokens=500)
119
+
120
+ if not result.report.faithful:
121
+ # budget too tight to hold every critical value — your call:
122
+ logger.warning("Quasar: %s", result.report.warnings)
123
+ result = opt.optimize(query, chunks, target_tokens=1000) # give it room
124
+
125
+ answer = llm(query, result.context)
126
+ ```
127
+
128
+ ### Configuration
129
+
130
+ ```python
131
+ from quasar import ContextOptimizer, OptimizerConfig
132
+
133
+ opt = ContextOptimizer(OptimizerConfig(
134
+ cost_per_1k_tokens=0.003, # your model's price, for the savings report
135
+ preserve_critical=True, # the faithfulness behavior (default on)
136
+ min_relevance=0.05, # drop sentences below this query relevance
137
+ model_name="all-MiniLM-L6-v2",
138
+ ))
139
+ ```
140
+
141
+ ### Custom critical patterns
142
+
143
+ Your domain has its own critical formats. Add them:
144
+
145
+ ```python
146
+ from quasar import core
147
+ core._CRITICAL_PATTERNS.append((r"\bCASE-\d{6}\b", "case_id"))
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Performance
153
+
154
+ - **~10–100 ms per call** after warm-up (embedding + greedy selection).
155
+ - **First call loads the model** (~30–60s, one time). Warm it at startup:
156
+ ```python
157
+ opt = ContextOptimizer()
158
+ opt.optimize("warmup", "warmup text.", target_tokens=50)
159
+ ```
160
+ - **8–13× faster than LLMLingua**, which runs a full neural model to compress.
161
+
162
+ ---
163
+
164
+ ## What Quasar is not
165
+
166
+ - **Not the best compressor by ratio.** Token-deletion methods compress harder.
167
+ They also rewrite your text.
168
+ - **Not an accuracy leader on pure QA.** A top-k filter matches or beats it there.
169
+ - **Not a guarantee against physics.** If your critical content is larger than
170
+ your token budget, it cannot all fit. Quasar preserves what it can *and tells
171
+ you what it couldn't* — that's the honest contract.
172
+
173
+ ---
174
+
175
+ ## License
176
+
177
+ MIT.
@@ -0,0 +1,36 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "quasar-context"
7
+ version = "0.1.0"
8
+ description = "Faithful context optimization for RAG apps — compress without corrupting critical data"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Sebastian Sabo" }]
13
+ keywords = ["rag", "llm", "context", "compression", "prompt", "embeddings"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
20
+ ]
21
+
22
+ dependencies = [
23
+ "sentence-transformers>=2.2.0",
24
+ "tiktoken>=0.5.0",
25
+ "numpy>=1.21.0",
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ dev = ["pytest>=7.0", "pytest-cov"]
30
+
31
+ [project.urls]
32
+ Homepage = "https://github.com/sebastiansabo/quasar"
33
+ Issues = "https://github.com/sebastiansabo/quasar/issues"
34
+
35
+ [tool.setuptools.packages.find]
36
+ include = ["quasar*"]
@@ -0,0 +1,35 @@
1
+ """
2
+ Quasar — faithful context optimization for RAG apps.
3
+
4
+ Compress retrieved context before your LLM call. Critical values
5
+ (prices, IBANs, dates, IDs, legal refs) are preserved verbatim when the
6
+ budget allows — and you get an explicit warning when it can't, instead of
7
+ silent corruption.
8
+
9
+ Quick start:
10
+ from quasar import ContextOptimizer
11
+
12
+ opt = ContextOptimizer()
13
+ result = opt.optimize(query, retrieved_chunks, target_tokens=500)
14
+
15
+ result.context # compressed context -> feed to your LLM
16
+ result.report.faithful # bool: did every critical value survive?
17
+ print(result.report.summary())
18
+ """
19
+
20
+ from .core import (
21
+ ContextOptimizer,
22
+ OptimizerConfig,
23
+ OptimizationResult,
24
+ OptimizationReport,
25
+ find_critical,
26
+ )
27
+
28
+ __version__ = "0.1.0"
29
+ __all__ = [
30
+ "ContextOptimizer",
31
+ "OptimizerConfig",
32
+ "OptimizationResult",
33
+ "OptimizationReport",
34
+ "find_critical",
35
+ ]
@@ -0,0 +1,296 @@
1
+ """
2
+ ================================================================================
3
+ quasar_layer.py -- Drop-in context optimization for RAG apps
4
+ ================================================================================
5
+ WHAT IT IS
6
+ ----------
7
+ A single layer you insert between retrieval and your LLM call. It:
8
+ 1. Picks the right compression strategy for the context automatically.
9
+ 2. GUARANTEES exact critical content (IDs, prices, dates, citations) survives
10
+ verbatim -- the one thing pure relevance ranking can't promise.
11
+ 3. Reports exactly what it did: tokens saved, est. cost saved, what was kept,
12
+ and any faithfulness risk it caught.
13
+
14
+ WHAT IS NOT
15
+ -----------
16
+ Not a magic compressor that beats everyone. Honest benchmarks showed
17
+ embedding-selection beats LLMLingua at far lower cost but ties/loses to simple
18
+ top-k on pure QA. So this layer's value is NOT "best compression" -- it is:
19
+ - zero-config: developer drops it in, no tuning
20
+ - safe-by-reporting: when budget can't fit all critical data, it does NOT
21
+ silently corrupt -- it preserves what fits and WARNS about what it dropped.
22
+ (No compressor can fit N critical facts into a budget smaller than them;
23
+ the honest behavior is to surface that, not hide it.)
24
+ - transparent: shows the savings + what the LLM actually sees
25
+ - cheap: embeddings, not an LLM-to-compress (8-13x faster than LLMLingua)
26
+
27
+ DESIGN PRINCIPLE
28
+ ----------------
29
+ The product is the DECISION + the PROOF, not the algorithm. Developers don't
30
+ know whether to compress, how much, or whether it's safe. This answers that
31
+ per-call, automatically, with receipts.
32
+
33
+ INSTALL
34
+ pip install sentence-transformers tiktoken
35
+
36
+ USE (the whole API is three lines)
37
+ from quasar_layer import ContextOptimizer
38
+ opt = ContextOptimizer()
39
+ result = opt.optimize(query, retrieved_chunks, target_tokens=500)
40
+ # result.context -> compressed context, feed to your LLM
41
+ # result.report -> tokens saved, cost saved, faithfulness status
42
+ ================================================================================
43
+ """
44
+ from __future__ import annotations
45
+ import re, time
46
+ from dataclasses import dataclass, field
47
+ from typing import Optional
48
+
49
+ # ---------- optional deps, graceful fallback ----------
50
+ try:
51
+ import tiktoken; _ENC = tiktoken.get_encoding("cl100k_base")
52
+ except Exception:
53
+ _ENC = None
54
+ def ntok(t: str) -> int:
55
+ if _ENC: return len(_ENC.encode(t))
56
+ return max(1, int(len(t.split()) * 1.3))
57
+
58
+ _MODEL = None
59
+ def _model(name="all-MiniLM-L6-v2"):
60
+ global _MODEL
61
+ if _MODEL is None:
62
+ from sentence_transformers import SentenceTransformer
63
+ _MODEL = SentenceTransformer(name)
64
+ return _MODEL
65
+
66
+
67
+ # =============================================================================
68
+ # CRITICAL CONTENT DETECTION (the faithfulness guarantee)
69
+ # =============================================================================
70
+ # Spans matching these MUST survive verbatim. Extensible by the developer.
71
+ _CRITICAL_PATTERNS = [
72
+ (r'[€$£¥]\s?\d[\d,.]*', "currency"),
73
+ (r'\b\d{1,3}(?:[,.]\d{3})+(?:\.\d+)?\b', "large_number"),
74
+ (r'\b[A-HJ-NPR-Z0-9]{17}\b', "vin"),
75
+ (r'\bRO\d{2}[A-Z0-9]{16,}\b', "iban"),
76
+ (r'\b[A-Z]{2}\d{2}[A-Z0-9]{10,}\b', "account"),
77
+ (r'\b\d{1,2}[/.\-]\d{1,2}[/.\-]\d{2,4}\b', "date"),
78
+ (r'\b(?:Order|Article|Regulation|Section|Clause|Directive)\s+[\w/.\-]+', "legal_ref"),
79
+ (r'\b[A-Z0-9]{6,}\-[A-Z0-9]{3,}\b', "code"),
80
+ (r'\b\d{6,}\b', "long_id"),
81
+ ]
82
+ def find_critical(text: str) -> list[str]:
83
+ hits = []
84
+ for pat, kind in _CRITICAL_PATTERNS:
85
+ for m in re.finditer(pat, text):
86
+ hits.append(m.group(0))
87
+ return hits
88
+
89
+
90
+ # =============================================================================
91
+ # RESULT + REPORT
92
+ # =============================================================================
93
+ @dataclass
94
+ class OptimizationReport:
95
+ tokens_in: int
96
+ tokens_out: int
97
+ tokens_saved: int
98
+ pct_saved: float
99
+ est_cost_saved_usd: float # at a configurable $/1k tokens
100
+ strategy: str # which path was taken + why
101
+ critical_found: int
102
+ critical_preserved: int
103
+ faithful: bool # all critical content survived?
104
+ warnings: list = field(default_factory=list)
105
+ optimize_ms: float = 0.0
106
+ def summary(self) -> str:
107
+ flag = "OK" if self.faithful else "FAITHFULNESS RISK"
108
+ return (f"[Quasar] {self.pct_saved:.0f}% smaller "
109
+ f"({self.tokens_in}->{self.tokens_out} tok, "
110
+ f"~${self.est_cost_saved_usd:.4f} saved) | "
111
+ f"strategy={self.strategy} | critical {self.critical_preserved}/{self.critical_found} {flag}"
112
+ + ("" if not self.warnings else f" | {len(self.warnings)} warning(s)"))
113
+
114
+ @dataclass
115
+ class OptimizationResult:
116
+ context: str
117
+ report: OptimizationReport
118
+
119
+
120
+ # =============================================================================
121
+ # THE OPTIMIZER
122
+ # =============================================================================
123
+ @dataclass
124
+ class OptimizerConfig:
125
+ cost_per_1k_tokens: float = 0.003 # for the savings estimate (set to your model)
126
+ skip_if_under: int = 0 # if context already <= target, don't touch it
127
+ min_relevance: float = 0.05 # drop sentences below this query relevance
128
+ preserve_critical: bool = True # the faithfulness guarantee (on by default)
129
+ model_name: str = "all-MiniLM-L6-v2"
130
+
131
+ class ContextOptimizer:
132
+ """
133
+ Drop-in: retrieved context in, optimized context out, with receipts.
134
+ Auto-selects strategy:
135
+ - context already within budget -> passthrough (no cost, no risk)
136
+ - context over budget -> faithful embedding-selection:
137
+ * reserve critical spans verbatim (guarantee)
138
+ * fill remaining budget by query relevance (the workhorse that
139
+ beat LLMLingua at a fraction of the cost)
140
+ """
141
+ def __init__(self, config: OptimizerConfig = OptimizerConfig()):
142
+ self.cfg = config
143
+
144
+ def _split(self, text: str) -> list[str]:
145
+ return [s.strip() for s in re.split(r'(?<=[.!?])\s+', text.strip()) if s.strip()]
146
+
147
+ def optimize(self, query: str, context, target_tokens: int = 500) -> OptimizationResult:
148
+ t0 = time.perf_counter()
149
+ # accept either a string or a list of chunks
150
+ if isinstance(context, (list, tuple)):
151
+ context = "\n".join(str(c) for c in context)
152
+ tokens_in = ntok(context)
153
+ crit_all = find_critical(context)
154
+
155
+ # ---- STEP 0: DEDUPE FIRST (always) ----
156
+ # Collapse identical sentences so we never spend budget on copies.
157
+ # This MUST run before the passthrough check: a context of 8 identical
158
+ # sentences may fit under the budget, but shipping 8 copies to the LLM
159
+ # wastes the very budget we exist to protect.
160
+ raw_sents = self._split(context)
161
+ seen = set(); sents = []
162
+ for s in raw_sents:
163
+ key = re.sub(r'\s+', ' ', s.strip().lower())
164
+ if key in seen: continue
165
+ seen.add(key); sents.append(s)
166
+ deduped = " ".join(sents)
167
+ tokens_deduped = ntok(deduped)
168
+ dupes_removed = len(raw_sents) - len(sents)
169
+
170
+ # ---- STRATEGY 1: passthrough if the DEDUPED context already fits ----
171
+ if tokens_deduped <= target_tokens:
172
+ saved = tokens_in - tokens_deduped
173
+ crit_kept = sum(1 for c in set(crit_all) if c in deduped)
174
+ strategy = ("passthrough (already within budget)" if dupes_removed == 0
175
+ else f"dedupe-only ({dupes_removed} duplicate sentence(s) removed)")
176
+ rep = OptimizationReport(
177
+ tokens_in, tokens_deduped, saved,
178
+ 100.0 * saved / max(1, tokens_in),
179
+ self.cfg.cost_per_1k_tokens * saved / 1000.0,
180
+ strategy=strategy,
181
+ critical_found=len(set(crit_all)),
182
+ critical_preserved=crit_kept,
183
+ faithful=(crit_kept == len(set(crit_all))),
184
+ optimize_ms=(time.perf_counter()-t0)*1000)
185
+ return OptimizationResult(deduped, rep)
186
+
187
+ # ---- STRATEGY 2: faithful embedding-selection ----
188
+ model = _model(self.cfg.model_name)
189
+ embs = model.encode([query] + sents, normalize_embeddings=True, show_progress_bar=False)
190
+ qv, svs = embs[0], embs[1:]
191
+ sims = svs @ qv
192
+ toks = [ntok(s) for s in sents]
193
+
194
+ chosen, used = [], 0
195
+ warnings = []
196
+
197
+ # 2a. reserve sentences containing critical spans (best-effort preservation)
198
+ if self.cfg.preserve_critical:
199
+ crit_idx = [i for i, s in enumerate(sents) if find_critical(s)]
200
+ # sort critical sentences by relevance so if budget is too tight we keep
201
+ # the most query-relevant critical ones first, and warn about drops
202
+ crit_idx.sort(key=lambda i: -sims[i])
203
+ for i in crit_idx:
204
+ if used + toks[i] <= target_tokens:
205
+ chosen.append(i); used += toks[i]
206
+ else:
207
+ warnings.append(f"critical sentence dropped (budget too tight): "
208
+ f"'{sents[i][:50]}...'")
209
+
210
+ # 2b. fill remaining budget with top relevance (skip already chosen + filler)
211
+ rest = [i for i in range(len(sents)) if i not in chosen]
212
+ rest.sort(key=lambda i: -sims[i])
213
+ for i in rest:
214
+ if float(sims[i]) < self.cfg.min_relevance: break
215
+ if used + toks[i] > target_tokens: continue
216
+ chosen.append(i); used += toks[i]
217
+
218
+ out_text = " ".join(sents[i] for i in sorted(chosen))
219
+ tokens_out = ntok(out_text)
220
+
221
+ # faithfulness audit: did every critical span survive verbatim?
222
+ crit_out = find_critical(out_text)
223
+ preserved = sum(1 for c in set(crit_all) if c in out_text)
224
+ faithful = (preserved == len(set(crit_all)))
225
+ if not faithful:
226
+ missing = [c for c in set(crit_all) if c not in out_text]
227
+ warnings.append(f"{len(missing)} critical value(s) not preserved: {missing[:3]}")
228
+
229
+ saved = tokens_in - tokens_out
230
+ rep = OptimizationReport(
231
+ tokens_in, tokens_out, saved,
232
+ 100.0 * saved / max(1, tokens_in),
233
+ self.cfg.cost_per_1k_tokens * saved / 1000.0,
234
+ strategy="faithful-selection (critical reserved + relevance fill)",
235
+ critical_found=len(set(crit_all)),
236
+ critical_preserved=preserved,
237
+ faithful=faithful,
238
+ warnings=warnings,
239
+ optimize_ms=(time.perf_counter()-t0)*1000)
240
+ return OptimizationResult(out_text, rep)
241
+
242
+ # --- convenience: wrap an LLM call so the developer gets one-line integration ---
243
+ def optimized_prompt(self, query: str, context, target_tokens=500,
244
+ template="Context:\n{context}\n\nQuestion: {query}\nAnswer:"):
245
+ res = self.optimize(query, context, target_tokens)
246
+ return template.format(context=res.context, query=query), res.report
247
+
248
+
249
+ # =============================================================================
250
+ # DEMO — shows the developer experience
251
+ # =============================================================================
252
+ def _demo():
253
+ sample_chunks = [
254
+ "The quarterly business review covered several operational topics across regions.",
255
+ "Market conditions have remained generally stable over the recent reporting period.",
256
+ "The invoice total amount due is €47,350.00 payable by 15/03/2026 per the agreement.",
257
+ "Various stakeholders provided feedback during the planning session last week.",
258
+ "The applicable regulation is Order 1802/2014 Article 7 governing this transaction.",
259
+ "Overall sector trends suggest continued steady commercial activity this year.",
260
+ "The vehicle identification number on record is WAUZZZ8K9BA123456 for this unit.",
261
+ "Documentation has been updated to reflect the latest procedural changes made.",
262
+ "The team continues to monitor performance metrics across all departments daily.",
263
+ "Payment should be remitted to IBAN RO49AAAA1B31007593840000 before the deadline.",
264
+ ] * 3 # triple it to force real compression
265
+
266
+ query = "What is the total amount due and the payment deadline?"
267
+
268
+ print("="*78)
269
+ print("QUASAR CONTEXT OPTIMIZER — developer experience demo")
270
+ print("="*78)
271
+ opt = ContextOptimizer(OptimizerConfig(cost_per_1k_tokens=0.003))
272
+
273
+ for budget in [120, 300]:
274
+ res = opt.optimize(query, sample_chunks, target_tokens=budget)
275
+ print(f"\n--- target_tokens={budget} ---")
276
+ print(res.report.summary())
277
+ print(f" optimize time: {res.report.optimize_ms:.0f} ms")
278
+ if res.report.warnings:
279
+ for w in res.report.warnings: print(f" ! {w}")
280
+ print(f" LLM now sees ({res.report.tokens_out} tok):")
281
+ print(f' "{res.context[:220]}..."')
282
+
283
+ print("\n" + "="*78)
284
+ print("THE PITCH (honest):")
285
+ print(" - 3-line drop-in: optimize(query, chunks, target_tokens)")
286
+ print(" - Auto-passthrough when context already fits (no needless cost/risk)")
287
+ print(" - Preserves critical values (prices, IBANs, dates, refs) verbatim when")
288
+ print(" budget allows -- and WARNS (never silently corrupts) when it can't")
289
+ print(" - Dedupes repeated content so budget isn't wasted on copies")
290
+ print(" - 8-13x cheaper to run than LLMLingua (embeddings, not an LLM)")
291
+ print(" - Every call returns receipts: tokens saved, $ saved, faithfulness status")
292
+ print(" - The product is the DECISION + PROOF, not a 'magic' compressor.")
293
+ print("="*78)
294
+
295
+ if __name__ == "__main__":
296
+ _demo()
@@ -0,0 +1,202 @@
1
+ Metadata-Version: 2.4
2
+ Name: quasar-context
3
+ Version: 0.1.0
4
+ Summary: Faithful context optimization for RAG apps — compress without corrupting critical data
5
+ Author: Sebastian Sabo
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/sebastiansabo/quasar
8
+ Project-URL: Issues, https://github.com/sebastiansabo/quasar/issues
9
+ Keywords: rag,llm,context,compression,prompt,embeddings
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Requires-Python: >=3.9
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: sentence-transformers>=2.2.0
19
+ Requires-Dist: tiktoken>=0.5.0
20
+ Requires-Dist: numpy>=1.21.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest>=7.0; extra == "dev"
23
+ Requires-Dist: pytest-cov; extra == "dev"
24
+ Dynamic: license-file
25
+
26
+ # Quasar
27
+
28
+ **Faithful context optimization for RAG apps.**
29
+
30
+ Compress retrieved context before your LLM call — without silently corrupting the
31
+ values that matter. Prices, IBANs, dates, invoice numbers, legal references and
32
+ IDs are preserved **verbatim** when the budget allows. When it doesn't, Quasar
33
+ **tells you** instead of quietly dropping them.
34
+
35
+ ```python
36
+ from quasar import ContextOptimizer
37
+
38
+ opt = ContextOptimizer()
39
+ result = opt.optimize(query, retrieved_chunks, target_tokens=500)
40
+
41
+ llm_answer(query, result.context) # feed the compressed context
42
+ print(result.report.summary())
43
+ # [Quasar] 63% smaller (1284->475 tok, ~$0.0024 saved) | critical 7/7 OK
44
+ ```
45
+
46
+ ---
47
+
48
+ ## Why this exists
49
+
50
+ Every context compressor optimizes for one thing: fewer tokens. None of them tell
51
+ you what they destroyed on the way.
52
+
53
+ If your RAG app retrieves an invoice and the compressor drops or mangles
54
+ `€47,350.00`, your LLM confidently answers with the wrong number and **you never
55
+ find out**. That's fine for a chatbot. It is not fine for finance, legal,
56
+ medical, compliance, or code.
57
+
58
+ Quasar makes one guarantee no other compressor makes:
59
+
60
+ > **It never silently corrupts your critical data.**
61
+ > Critical values survive verbatim, or you get an explicit warning.
62
+
63
+ ---
64
+
65
+ ## What it does
66
+
67
+ 1. **Detects critical spans** — currency, IBANs, dates, VINs, long IDs, legal
68
+ references, contract codes — by pattern.
69
+ 2. **Reserves them verbatim.** Critical sentences claim budget first and are
70
+ never rewritten. (Token-deletion compressors *rewrite* text — that's how they
71
+ corrupt exact values.)
72
+ 3. **Fills the remaining budget by relevance**, using embedding similarity to the
73
+ query. Filler is dropped.
74
+ 4. **Dedupes** repeated sentences so budget isn't wasted on copies.
75
+ 5. **Audits and reports.** Every call returns tokens saved, cost saved, and a
76
+ faithfulness status — with warnings naming any critical value it couldn't fit.
77
+
78
+ ---
79
+
80
+ ## Honest benchmarks
81
+
82
+ Measured on LongBench (narrativeqa / qasper / hotpotqa, N=30 per task), real LLM
83
+ judge, token-F1 scoring.
84
+
85
+ **Where Quasar wins:**
86
+
87
+ | Matchup | Result |
88
+ |---|---|
89
+ | vs **truncation** | **9–0** — wins at every task and budget |
90
+ | vs **LLMLingua** | **6–0** on accuracy, **8–13× faster** to compress |
91
+ | Long contexts | Handles 17k+ word documents LLMLingua **cannot process at all** |
92
+
93
+ LLMLingua runs a neural model to compress. Quasar runs embeddings. Same or better
94
+ accuracy, a fraction of the compute.
95
+
96
+ **Where Quasar does not win — stated plainly:**
97
+
98
+ Against a **pure top-k embedding filter** (e.g. LangChain's `EmbeddingsFilter`),
99
+ Quasar goes **3–6** on raw QA accuracy. On pure question-answering, simple
100
+ relevance ranking is competitive or better.
101
+
102
+ **So Quasar is not the accuracy leader on QA, and doesn't claim to be.** Its value
103
+ is the axis those benchmarks don't measure: *faithfulness*. A top-k filter has no
104
+ concept of critical data — it drops a low-relevance sentence containing your
105
+ invoice number without hesitation, and never tells you. Quasar reserves it, and
106
+ warns when it can't.
107
+
108
+ **Use Quasar when correctness of exact values matters more than the last 2% of
109
+ retrieval F1.** If you're building a general chatbot and only care about QA
110
+ accuracy, use a top-k filter — it's simpler and we'll say so.
111
+
112
+ ---
113
+
114
+ ## Install
115
+
116
+ ```bash
117
+ pip install quasar-context
118
+ ```
119
+
120
+ ## Usage
121
+
122
+ ### Basic
123
+
124
+ ```python
125
+ from quasar import ContextOptimizer
126
+
127
+ opt = ContextOptimizer() # loads the embedding model once
128
+ result = opt.optimize(
129
+ query="What is the total due and the deadline?",
130
+ context=retrieved_chunks, # str or list[str]
131
+ target_tokens=500,
132
+ )
133
+
134
+ result.context # compressed text for your LLM
135
+ result.report.tokens_saved # int
136
+ result.report.faithful # bool — did all critical values survive?
137
+ result.report.warnings # list[str] — what got dropped and why
138
+ ```
139
+
140
+ ### Guarding a production call
141
+
142
+ ```python
143
+ result = opt.optimize(query, chunks, target_tokens=500)
144
+
145
+ if not result.report.faithful:
146
+ # budget too tight to hold every critical value — your call:
147
+ logger.warning("Quasar: %s", result.report.warnings)
148
+ result = opt.optimize(query, chunks, target_tokens=1000) # give it room
149
+
150
+ answer = llm(query, result.context)
151
+ ```
152
+
153
+ ### Configuration
154
+
155
+ ```python
156
+ from quasar import ContextOptimizer, OptimizerConfig
157
+
158
+ opt = ContextOptimizer(OptimizerConfig(
159
+ cost_per_1k_tokens=0.003, # your model's price, for the savings report
160
+ preserve_critical=True, # the faithfulness behavior (default on)
161
+ min_relevance=0.05, # drop sentences below this query relevance
162
+ model_name="all-MiniLM-L6-v2",
163
+ ))
164
+ ```
165
+
166
+ ### Custom critical patterns
167
+
168
+ Your domain has its own critical formats. Add them:
169
+
170
+ ```python
171
+ from quasar import core
172
+ core._CRITICAL_PATTERNS.append((r"\bCASE-\d{6}\b", "case_id"))
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Performance
178
+
179
+ - **~10–100 ms per call** after warm-up (embedding + greedy selection).
180
+ - **First call loads the model** (~30–60s, one time). Warm it at startup:
181
+ ```python
182
+ opt = ContextOptimizer()
183
+ opt.optimize("warmup", "warmup text.", target_tokens=50)
184
+ ```
185
+ - **8–13× faster than LLMLingua**, which runs a full neural model to compress.
186
+
187
+ ---
188
+
189
+ ## What Quasar is not
190
+
191
+ - **Not the best compressor by ratio.** Token-deletion methods compress harder.
192
+ They also rewrite your text.
193
+ - **Not an accuracy leader on pure QA.** A top-k filter matches or beats it there.
194
+ - **Not a guarantee against physics.** If your critical content is larger than
195
+ your token budget, it cannot all fit. Quasar preserves what it can *and tells
196
+ you what it couldn't* — that's the honest contract.
197
+
198
+ ---
199
+
200
+ ## License
201
+
202
+ MIT.
@@ -0,0 +1,11 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ quasar/__init__.py
5
+ quasar/core.py
6
+ quasar_context.egg-info/PKG-INFO
7
+ quasar_context.egg-info/SOURCES.txt
8
+ quasar_context.egg-info/dependency_links.txt
9
+ quasar_context.egg-info/requires.txt
10
+ quasar_context.egg-info/top_level.txt
11
+ tests/test_core.py
@@ -0,0 +1,7 @@
1
+ sentence-transformers>=2.2.0
2
+ tiktoken>=0.5.0
3
+ numpy>=1.21.0
4
+
5
+ [dev]
6
+ pytest>=7.0
7
+ pytest-cov
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,108 @@
1
+ """
2
+ Tests for Quasar. The critical ones assert the FAITHFULNESS CONTRACT:
3
+ - critical values survive verbatim when budget allows
4
+ - when budget is too tight, the report says so (never silent)
5
+ If these fail, the product's only differentiator is broken.
6
+ """
7
+ import pytest
8
+ from quasar import ContextOptimizer, OptimizerConfig, find_critical
9
+
10
+
11
+ # ---------------------------------------------------------------- fixtures
12
+ @pytest.fixture(scope="module")
13
+ def opt():
14
+ return ContextOptimizer(OptimizerConfig(cost_per_1k_tokens=0.003))
15
+
16
+
17
+ CRITICAL_CHUNKS = [
18
+ "The quarterly business review covered several operational topics.",
19
+ "The invoice total amount due is €47,350.00 payable by 15/03/2026.",
20
+ "Market conditions have remained generally stable this period.",
21
+ "Payment should be remitted to IBAN RO49AAAA1B31007593840000 promptly.",
22
+ "The team continues to monitor performance metrics across departments.",
23
+ "The applicable regulation is Order 1802/2014 governing this deal.",
24
+ "Documentation has been updated to reflect procedural changes made.",
25
+ ]
26
+ QUERY = "What is the total amount due and the payment deadline?"
27
+
28
+
29
+ # ---------------------------------------------------------------- detection
30
+ def test_finds_currency():
31
+ assert any("47,350" in c for c in find_critical("Total is €47,350.00 due now."))
32
+
33
+ def test_finds_iban():
34
+ hits = find_critical("Send to RO49AAAA1B31007593840000 today.")
35
+ assert any("RO49AAAA" in h for h in hits)
36
+
37
+ def test_finds_date():
38
+ assert find_critical("Due by 15/03/2026 without fail.")
39
+
40
+ def test_ignores_plain_prose():
41
+ assert find_critical("The weather today is mild and pleasant.") == []
42
+
43
+
44
+ # ---------------------------------------------------------------- the contract
45
+ def test_critical_preserved_when_budget_allows(opt):
46
+ """THE core claim: with room, every critical value survives verbatim."""
47
+ res = opt.optimize(QUERY, CRITICAL_CHUNKS, target_tokens=300)
48
+ assert res.report.faithful, f"critical data lost: {res.report.warnings}"
49
+ assert "€47,350.00" in res.context
50
+ assert "RO49AAAA1B31007593840000" in res.context
51
+ assert "15/03/2026" in res.context
52
+ assert res.report.critical_preserved == res.report.critical_found
53
+
54
+ def test_warns_when_budget_too_tight(opt):
55
+ """THE honesty claim: if it can't fit critical data, it MUST say so."""
56
+ res = opt.optimize(QUERY, CRITICAL_CHUNKS, target_tokens=15)
57
+ if not res.report.faithful:
58
+ assert res.report.warnings, "dropped critical data but issued NO warning"
59
+ assert res.report.critical_preserved < res.report.critical_found
60
+
61
+ def test_never_silently_drops(opt):
62
+ """faithful==False must always be accompanied by warnings."""
63
+ for budget in (10, 20, 30, 50, 80, 200, 400):
64
+ res = opt.optimize(QUERY, CRITICAL_CHUNKS, target_tokens=budget)
65
+ if not res.report.faithful:
66
+ assert res.report.warnings, f"silent drop at budget={budget}"
67
+
68
+
69
+ # ---------------------------------------------------------------- behavior
70
+ def test_passthrough_when_already_small(opt):
71
+ res = opt.optimize(QUERY, "Short context.", target_tokens=500)
72
+ assert "passthrough" in res.report.strategy
73
+ assert res.report.tokens_saved == 0
74
+ assert res.report.faithful
75
+
76
+ def test_actually_compresses(opt):
77
+ big = CRITICAL_CHUNKS * 6
78
+ res = opt.optimize(QUERY, big, target_tokens=200)
79
+ assert res.report.tokens_out <= 200
80
+ assert res.report.tokens_saved > 0
81
+ assert res.report.pct_saved > 0
82
+
83
+ def test_dedupes_repeats(opt):
84
+ """Duplicate sentences must not each consume budget."""
85
+ dupes = ["The invoice total amount due is €47,350.00 payable soon."] * 8
86
+ res = opt.optimize(QUERY, dupes, target_tokens=100)
87
+ assert res.context.count("€47,350.00") == 1, "kept duplicate critical sentences"
88
+
89
+ def test_accepts_string_or_list(opt):
90
+ as_list = opt.optimize(QUERY, CRITICAL_CHUNKS, target_tokens=200)
91
+ as_str = opt.optimize(QUERY, " ".join(CRITICAL_CHUNKS), target_tokens=200)
92
+ assert as_list.report.tokens_out == as_str.report.tokens_out
93
+
94
+
95
+ # ---------------------------------------------------------------- report
96
+ def test_report_is_complete(opt):
97
+ res = opt.optimize(QUERY, CRITICAL_CHUNKS * 4, target_tokens=150)
98
+ r = res.report
99
+ assert r.tokens_in > r.tokens_out
100
+ assert r.tokens_saved == r.tokens_in - r.tokens_out
101
+ assert 0 <= r.pct_saved <= 100
102
+ assert r.est_cost_saved_usd >= 0
103
+ assert isinstance(r.faithful, bool)
104
+ assert r.summary()
105
+
106
+ def test_empty_context_does_not_crash(opt):
107
+ res = opt.optimize(QUERY, "", target_tokens=100)
108
+ assert res.context == "" or res.report.faithful