invaria 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,34 @@
1
+ # Local batch testing files
2
+ batch_test.py
3
+ batch_prompts.txt
4
+ batch_result.txt
5
+
6
+ # Environments & Package Management
7
+ .venv
8
+ venv/
9
+ env/
10
+ uv.lock
11
+
12
+ # Python Cache
13
+ __pycache__/
14
+ *.py[cod]
15
+ *$py.class
16
+
17
+ # Distribution / Packaging
18
+ build/
19
+ dist/
20
+ *.egg-info/
21
+ .eggs/
22
+ *.egg
23
+
24
+ # Testing
25
+ .pytest_cache/
26
+ .coverage
27
+ htmlcov/
28
+
29
+ # IDE / OS
30
+ .vscode/
31
+ .idea/
32
+ .DS_Store
33
+
34
+ .gitignore
invaria-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 sgindeed
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.
invaria-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,175 @@
1
+ Metadata-Version: 2.5
2
+ Name: invaria
3
+ Version: 0.1.0
4
+ Summary: Invaria — Universal LLM Context Compiler
5
+ Project-URL: Homepage, https://github.com/sgindeed/invaria
6
+ Project-URL: Repository, https://github.com/sgindeed/invaria
7
+ Author-email: Supratim Ghosh <sgindeed234@gmail.com>
8
+ License: MIT
9
+ License-File: LICENSE
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: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: pydantic>=2.0.0
20
+ Provides-Extra: anthropic
21
+ Requires-Dist: anthropic>=0.18.0; extra == 'anthropic'
22
+ Provides-Extra: cli
23
+ Requires-Dist: typer>=0.9.0; extra == 'cli'
24
+ Provides-Extra: google
25
+ Requires-Dist: google-genai>=0.3.0; extra == 'google'
26
+ Provides-Extra: openai
27
+ Requires-Dist: openai>=1.0.0; extra == 'openai'
28
+ Provides-Extra: test
29
+ Requires-Dist: hypothesis>=6.0.0; extra == 'test'
30
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == 'test'
31
+ Requires-Dist: pytest>=7.0.0; extra == 'test'
32
+ Description-Content-Type: text/markdown
33
+
34
+ # Invaria — Universal LLM Context Compiler
35
+
36
+ > **Compress less. Preserve more. Prove everything.**
37
+
38
+ [![PyPI version](https://img.shields.io/pypi/v/invaria.svg)](https://pypi.org/project/invaria/)
39
+ [![Python versions](https://img.shields.io/pypi/pyversions/invaria.svg)](https://pypi.org/project/invaria/)
40
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
41
+
42
+ **Invaria** is a deterministic, rule-based context compiler for Large Language Models.
43
+
44
+ Instead of blindly dropping tokens based on probabilistic attention scores (which often leads to hallucinated numbers, broken URLs, or lost named entities), Invaria treats your prompt as source code. It compiles the context into an intermediate representation (IR), generates compression candidates, **verifies** that strict preservation contracts are met, and emits the cheapest safe representation.
45
+
46
+ ---
47
+
48
+ ## Why Invaria?
49
+
50
+ Most prompt compressors use smaller ML models to guess which words are "unimportant." This is dangerous for enterprise use cases where missing a "NOT", dropping a crucial ID, or altering a currency amount is catastrophic.
51
+
52
+ Invaria introduces a **Verification Engine**. It mathematically guarantees that:
53
+ * ✅ **Numerical Invariants** (e.g., `$5000`, `99%`, `0.001`) are preserved.
54
+ * ✅ **Lexical Entities** (Proper nouns, CamelCase, Acronyms) are untouched.
55
+ * ✅ **Structured Identifiers** (URLs, Email addresses, API Keys, UUIDs) are safely retained.
56
+ * ✅ **Formatting** (Markdown tables, JSON structures, code blocks) remains syntactically valid.
57
+
58
+ If a compressed candidate drops a required invariant, Invaria rejects it.
59
+
60
+ ---
61
+
62
+ ## Installation
63
+
64
+ Install via pip. Invaria `v0.1.0` is extremely lightweight and relies primarily on `pydantic`.
65
+
66
+ ```bash
67
+ pip install invaria
68
+ ```
69
+
70
+ *Note: Optional dependencies for ML-based semantic compression (`openai`, `anthropic`, `google`) will be utilized in upcoming releases.*
71
+
72
+ ---
73
+
74
+ ## Python API Quickstart
75
+
76
+ Invaria is designed to be easily integrated into your existing LLM pipelines, RAG systems, or agent frameworks.
77
+
78
+ ```python
79
+ from invaria import Invaria
80
+
81
+ # Initialize the compiler
82
+ compiler = Invaria(mode="invariant")
83
+
84
+ text = """
85
+ User Alice transferred $5,000 to Bob on Monday...
86
+ Please do not delete the backup files!!! They are stored in Amazon S3.
87
+ """
88
+
89
+ # Compress the context
90
+ result = compiler.compress(text)
91
+
92
+ # The compressed text
93
+ print(result.text)
94
+ # Output: "User Alice transferred $5,000 to Bob on Monday. Please do not delete the backup files! They are stored in Amazon S3."
95
+
96
+ # Access detailed metrics
97
+ print(f"Original Tokens: {result.original_tokens}")
98
+ print(f"Compressed Tokens: {result.compressed_tokens}")
99
+ print(f"Token Reduction: {result.token_reduction}")
100
+ print(f"Compression Ratio: {result.compression_ratio:.2f}x")
101
+
102
+ # Cryptographic proof of preservation
103
+ print(f"Verified Safe: {result.proof.verified}")
104
+ print(f"Preserved Entities:{result.proof.preserved}")
105
+ ```
106
+
107
+ ### Inspecting Extracted Invariants
108
+
109
+ You can also use Invaria just to parse and inspect the semantic constraints within a prompt without compressing it:
110
+
111
+ ```python
112
+ ir = compiler.compile("Contact Support at help@example.com if Stripe webhooks fail.")
113
+
114
+ for node_id, node in ir.nodes.items():
115
+ print(f"Type: {node.type} | Value: {node.value}")
116
+ # Type: entity | Value: Contact
117
+ # Type: entity | Value: Support
118
+ # Type: entity | Value: help@example.com
119
+ # Type: entity | Value: Stripe
120
+ ```
121
+
122
+ ---
123
+
124
+ ## CLI Usage
125
+
126
+ Invaria comes with a built-in Command Line Interface for quickly compressing files or verifying external compressions in your CI/CD pipelines.
127
+
128
+ ### Compress a File
129
+ ```bash
130
+ invaria compress prompt.txt --mode invariant
131
+ ```
132
+ *Outputs the compression metrics, the cryptographic proof status, and the compressed text.*
133
+
134
+ ### Verify a Compression
135
+ If you have an original context and a compressed version, Invaria can verify if the compressed version safely retained all necessary invariants from the original:
136
+ ```bash
137
+ invaria verify original.txt compressed.txt
138
+ ```
139
+ *Outputs `Verification Passed: True` or `False`.*
140
+
141
+ ---
142
+
143
+ ## Compiler Architecture
144
+
145
+ Invaria operates similarly to a traditional programming language compiler:
146
+
147
+ ```mermaid
148
+ graph LR
149
+ A[Text Input] --> B(COMPILE)
150
+ B -->|Semantic IR| C(OPTIMIZE)
151
+ C -->|Generate Candidates| D(VERIFY)
152
+ D -->|Check Constraints| E(EMIT)
153
+ E --> F[Verified Compressed Text]
154
+ ```
155
+
156
+ 1. **Compile (Extract Invariants):** Scans the text to build a `SemanticGraph` (IR) identifying all Entities, Numerical Invariants, Dates, and Instructions.
157
+ 2. **Optimize (Generate Candidates):** Applies active compressors (like `LexicalCompressor` for whitespace/punctuation normalization).
158
+ 3. **Verify (Preservation Contract):** The `VerificationEngine` checks the candidate string against the Semantic IR to ensure zero critical tokens were lost or mutated.
159
+ 4. **Emit:** Computes SHA-256 hashes for the proof, calculates token reductions, and returns a `CompressionResult`.
160
+
161
+ ---
162
+
163
+ ## Roadmap
164
+
165
+ * **v0.1.x (Current):** Deterministic Lexical Compression, Entity/Numerical Invariant Extraction, Core Verification Engine, CLI.
166
+ * **v0.2.x:** Syntactic Compression (safe removal of filler phrases, stop words) and Tiktoken integration for exact token pricing.
167
+ * **v0.3.x:** Abstractive Semantic Compression using LLM providers (`openai`, `anthropic`, `google`) backed by Invaria's deterministic `VerificationEngine` to prevent LLM hallucinations during summarization.
168
+
169
+ ---
170
+
171
+ ## License
172
+
173
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
174
+
175
+ Copyright (c) 2026 Supratim Ghosh & Invaria Contributors.
@@ -0,0 +1,142 @@
1
+ # Invaria — Universal LLM Context Compiler
2
+
3
+ > **Compress less. Preserve more. Prove everything.**
4
+
5
+ [![PyPI version](https://img.shields.io/pypi/v/invaria.svg)](https://pypi.org/project/invaria/)
6
+ [![Python versions](https://img.shields.io/pypi/pyversions/invaria.svg)](https://pypi.org/project/invaria/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
8
+
9
+ **Invaria** is a deterministic, rule-based context compiler for Large Language Models.
10
+
11
+ Instead of blindly dropping tokens based on probabilistic attention scores (which often leads to hallucinated numbers, broken URLs, or lost named entities), Invaria treats your prompt as source code. It compiles the context into an intermediate representation (IR), generates compression candidates, **verifies** that strict preservation contracts are met, and emits the cheapest safe representation.
12
+
13
+ ---
14
+
15
+ ## Why Invaria?
16
+
17
+ Most prompt compressors use smaller ML models to guess which words are "unimportant." This is dangerous for enterprise use cases where missing a "NOT", dropping a crucial ID, or altering a currency amount is catastrophic.
18
+
19
+ Invaria introduces a **Verification Engine**. It mathematically guarantees that:
20
+ * ✅ **Numerical Invariants** (e.g., `$5000`, `99%`, `0.001`) are preserved.
21
+ * ✅ **Lexical Entities** (Proper nouns, CamelCase, Acronyms) are untouched.
22
+ * ✅ **Structured Identifiers** (URLs, Email addresses, API Keys, UUIDs) are safely retained.
23
+ * ✅ **Formatting** (Markdown tables, JSON structures, code blocks) remains syntactically valid.
24
+
25
+ If a compressed candidate drops a required invariant, Invaria rejects it.
26
+
27
+ ---
28
+
29
+ ## Installation
30
+
31
+ Install via pip. Invaria `v0.1.0` is extremely lightweight and relies primarily on `pydantic`.
32
+
33
+ ```bash
34
+ pip install invaria
35
+ ```
36
+
37
+ *Note: Optional dependencies for ML-based semantic compression (`openai`, `anthropic`, `google`) will be utilized in upcoming releases.*
38
+
39
+ ---
40
+
41
+ ## Python API Quickstart
42
+
43
+ Invaria is designed to be easily integrated into your existing LLM pipelines, RAG systems, or agent frameworks.
44
+
45
+ ```python
46
+ from invaria import Invaria
47
+
48
+ # Initialize the compiler
49
+ compiler = Invaria(mode="invariant")
50
+
51
+ text = """
52
+ User Alice transferred $5,000 to Bob on Monday...
53
+ Please do not delete the backup files!!! They are stored in Amazon S3.
54
+ """
55
+
56
+ # Compress the context
57
+ result = compiler.compress(text)
58
+
59
+ # The compressed text
60
+ print(result.text)
61
+ # Output: "User Alice transferred $5,000 to Bob on Monday. Please do not delete the backup files! They are stored in Amazon S3."
62
+
63
+ # Access detailed metrics
64
+ print(f"Original Tokens: {result.original_tokens}")
65
+ print(f"Compressed Tokens: {result.compressed_tokens}")
66
+ print(f"Token Reduction: {result.token_reduction}")
67
+ print(f"Compression Ratio: {result.compression_ratio:.2f}x")
68
+
69
+ # Cryptographic proof of preservation
70
+ print(f"Verified Safe: {result.proof.verified}")
71
+ print(f"Preserved Entities:{result.proof.preserved}")
72
+ ```
73
+
74
+ ### Inspecting Extracted Invariants
75
+
76
+ You can also use Invaria just to parse and inspect the semantic constraints within a prompt without compressing it:
77
+
78
+ ```python
79
+ ir = compiler.compile("Contact Support at help@example.com if Stripe webhooks fail.")
80
+
81
+ for node_id, node in ir.nodes.items():
82
+ print(f"Type: {node.type} | Value: {node.value}")
83
+ # Type: entity | Value: Contact
84
+ # Type: entity | Value: Support
85
+ # Type: entity | Value: help@example.com
86
+ # Type: entity | Value: Stripe
87
+ ```
88
+
89
+ ---
90
+
91
+ ## CLI Usage
92
+
93
+ Invaria comes with a built-in Command Line Interface for quickly compressing files or verifying external compressions in your CI/CD pipelines.
94
+
95
+ ### Compress a File
96
+ ```bash
97
+ invaria compress prompt.txt --mode invariant
98
+ ```
99
+ *Outputs the compression metrics, the cryptographic proof status, and the compressed text.*
100
+
101
+ ### Verify a Compression
102
+ If you have an original context and a compressed version, Invaria can verify if the compressed version safely retained all necessary invariants from the original:
103
+ ```bash
104
+ invaria verify original.txt compressed.txt
105
+ ```
106
+ *Outputs `Verification Passed: True` or `False`.*
107
+
108
+ ---
109
+
110
+ ## Compiler Architecture
111
+
112
+ Invaria operates similarly to a traditional programming language compiler:
113
+
114
+ ```mermaid
115
+ graph LR
116
+ A[Text Input] --> B(COMPILE)
117
+ B -->|Semantic IR| C(OPTIMIZE)
118
+ C -->|Generate Candidates| D(VERIFY)
119
+ D -->|Check Constraints| E(EMIT)
120
+ E --> F[Verified Compressed Text]
121
+ ```
122
+
123
+ 1. **Compile (Extract Invariants):** Scans the text to build a `SemanticGraph` (IR) identifying all Entities, Numerical Invariants, Dates, and Instructions.
124
+ 2. **Optimize (Generate Candidates):** Applies active compressors (like `LexicalCompressor` for whitespace/punctuation normalization).
125
+ 3. **Verify (Preservation Contract):** The `VerificationEngine` checks the candidate string against the Semantic IR to ensure zero critical tokens were lost or mutated.
126
+ 4. **Emit:** Computes SHA-256 hashes for the proof, calculates token reductions, and returns a `CompressionResult`.
127
+
128
+ ---
129
+
130
+ ## Roadmap
131
+
132
+ * **v0.1.x (Current):** Deterministic Lexical Compression, Entity/Numerical Invariant Extraction, Core Verification Engine, CLI.
133
+ * **v0.2.x:** Syntactic Compression (safe removal of filler phrases, stop words) and Tiktoken integration for exact token pricing.
134
+ * **v0.3.x:** Abstractive Semantic Compression using LLM providers (`openai`, `anthropic`, `google`) backed by Invaria's deterministic `VerificationEngine` to prevent LLM hallucinations during summarization.
135
+
136
+ ---
137
+
138
+ ## License
139
+
140
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
141
+
142
+ Copyright (c) 2026 Supratim Ghosh & Invaria Contributors.
@@ -0,0 +1,66 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "invaria"
7
+ version = "0.1.0"
8
+ description = "Invaria — Universal LLM Context Compiler"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [
13
+ { name = "Supratim Ghosh", email = "sgindeed234@gmail.com" }
14
+ ]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.10",
21
+ "Programming Language :: Python :: 3.11",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ ]
25
+ dependencies = [
26
+ "pydantic>=2.0.0"
27
+ ]
28
+
29
+ [project.optional-dependencies]
30
+ openai = [
31
+ "openai>=1.0.0"
32
+ ]
33
+ anthropic = [
34
+ "anthropic>=0.18.0"
35
+ ]
36
+ google = [
37
+ "google-genai>=0.3.0"
38
+ ]
39
+ cli = [
40
+ "typer>=0.9.0"
41
+ ]
42
+ test = [
43
+ "pytest>=7.0.0",
44
+ "hypothesis>=6.0.0",
45
+ "pytest-asyncio>=0.21.0"
46
+ ]
47
+
48
+ [project.urls]
49
+ Homepage = "https://github.com/sgindeed/invaria"
50
+ Repository = "https://github.com/sgindeed/invaria"
51
+
52
+ [project.scripts]
53
+ invaria = "invaria.cli.main:main"
54
+
55
+ [tool.pytest.ini_options]
56
+ minversion = "7.0"
57
+ addopts = "-ra -q"
58
+ testpaths = ["tests"]
59
+ asyncio_mode = "strict"
60
+
61
+ [tool.ruff]
62
+ line-length = 88
63
+ target-version = "py310"
64
+
65
+ [tool.hatch.build.targets.wheel]
66
+ packages = ["src/invaria"]
@@ -0,0 +1,4 @@
1
+ from .api import Invaria
2
+
3
+ __version__ = "0.1.0"
4
+ __all__ = ["Invaria"]
@@ -0,0 +1,31 @@
1
+ from typing import Optional
2
+ from .config import InvariaConfig
3
+ from .compiler.pipeline import CompilerPipeline, CompressionResult
4
+ from .ir.models import SemanticGraph
5
+
6
+ class Invaria:
7
+ def __init__(self, **kwargs):
8
+ self.config = InvariaConfig(**kwargs)
9
+ self.pipeline = CompilerPipeline(self.config)
10
+
11
+ def compress(self, text: str, **kwargs) -> CompressionResult:
12
+ # Override config optionally for this run
13
+ if kwargs:
14
+ local_config = self.config.model_copy(update=kwargs)
15
+ local_pipeline = CompilerPipeline(local_config)
16
+ return local_pipeline.compress(text)
17
+ return self.pipeline.compress(text)
18
+
19
+ def compile(self, text: str) -> SemanticGraph:
20
+ return self.pipeline.compile(text)
21
+
22
+ def verify(self, original: str, compressed: str) -> bool:
23
+ ir = self.pipeline.compile(original)
24
+ report = self.pipeline.verifier.verify(ir, compressed)
25
+ return report.passed
26
+
27
+ def inspect(self, text: str) -> SemanticGraph:
28
+ return self.pipeline.compile(text)
29
+
30
+ def benchmark(self, text: str) -> None:
31
+ raise NotImplementedError("Benchmark framework is not yet initialized.")
@@ -0,0 +1,49 @@
1
+ import argparse
2
+ import sys
3
+ from ..api import Invaria
4
+
5
+ def main():
6
+ parser = argparse.ArgumentParser(description="Invaria — Universal LLM Context Compiler")
7
+ subparsers = parser.add_subparsers(dest="command")
8
+
9
+ compress_parser = subparsers.add_parser("compress", help="Compress a context")
10
+ compress_parser.add_argument("input_file", help="Input file path")
11
+ compress_parser.add_argument("--mode", default="invariant", help="Compression mode")
12
+
13
+ verify_parser = subparsers.add_parser("verify", help="Verify a compressed context")
14
+ verify_parser.add_argument("original", help="Original context file")
15
+ verify_parser.add_argument("compressed", help="Compressed context file")
16
+
17
+ args = parser.parse_args()
18
+
19
+ if not args.command:
20
+ parser.print_help()
21
+ sys.exit(1)
22
+
23
+ compiler = Invaria()
24
+
25
+ if args.command == "compress":
26
+ with open(args.input_file, 'r', encoding='utf-8') as f:
27
+ text = f.read()
28
+
29
+ result = compiler.compress(text, mode=args.mode)
30
+
31
+ print(f"Original tokens (approx): {result.original_tokens}")
32
+ print(f"Compressed tokens (approx): {result.compressed_tokens}")
33
+ print(f"Reduction: {result.token_reduction}")
34
+ print(f"Ratio: {result.compression_ratio:.2f}")
35
+ print(f"Verified: {result.proof.verified}")
36
+ print("\n--- COMPRESSED OUTPUT ---")
37
+ print(result.text)
38
+
39
+ elif args.command == "verify":
40
+ with open(args.original, 'r', encoding='utf-8') as f:
41
+ orig_text = f.read()
42
+ with open(args.compressed, 'r', encoding='utf-8') as f:
43
+ comp_text = f.read()
44
+
45
+ is_valid = compiler.verify(orig_text, comp_text)
46
+ print(f"Verification Passed: {is_valid}")
47
+
48
+ if __name__ == "__main__":
49
+ main()
@@ -0,0 +1,244 @@
1
+ import hashlib
2
+ import json
3
+ import re
4
+ from typing import List, Dict, Any
5
+ from pydantic import BaseModel
6
+
7
+ from ..config import InvariaConfig
8
+ from ..ir.models import (
9
+ SemanticGraph,
10
+ Entity,
11
+ NumericalInvariant,
12
+ SourceSpan,
13
+ )
14
+ from ..compressors.lexical import LexicalCompressor
15
+ from ..verification.verifier import VerificationEngine
16
+ from ..verification.contract import PreservationContract
17
+ from ..verification.report import CompressionProof
18
+ from ..optimizer.search import Optimizer
19
+
20
+
21
+ class CompressionResult(BaseModel):
22
+ text: str
23
+ original_tokens: int
24
+ compressed_tokens: int
25
+ token_reduction: int
26
+ compression_ratio: float
27
+ mode: str
28
+ representation: str
29
+ proof: CompressionProof
30
+ invariants: List[Any]
31
+ warnings: List[str]
32
+ metadata: Dict[str, Any]
33
+
34
+
35
+ class CompilerPipeline:
36
+ # Matches words, numbers with currency/units/decimals, times, emails, and identifiers
37
+ _TOKEN_PATTERN = re.compile(
38
+ r"[A-Za-z0-9_$%+-]+(?:[@.:/-][A-Za-z0-9_$%+-]+)*"
39
+ )
40
+
41
+ def __init__(self, config: InvariaConfig):
42
+ self.config = config
43
+ self.compressors = [LexicalCompressor()]
44
+ self.contract = PreservationContract(strictness=config.mode)
45
+ self.verifier = VerificationEngine(self.contract)
46
+ self.optimizer = Optimizer(config)
47
+ self._compressor_map = {c.name: c for c in self.compressors}
48
+
49
+ @staticmethod
50
+ def _hash_text(text: str) -> str:
51
+ return hashlib.sha256(text.encode("utf-8")).hexdigest()[:16]
52
+
53
+ @staticmethod
54
+ def _hash_ir(ir: SemanticGraph) -> str:
55
+ payload = json.dumps(
56
+ {k: v.model_dump() for k, v in sorted(ir.nodes.items())},
57
+ sort_keys=True,
58
+ default=str,
59
+ )
60
+ return hashlib.sha256(payload.encode("utf-8")).hexdigest()[:16]
61
+
62
+ def extract_invariants(self, text: str) -> SemanticGraph:
63
+ graph = SemanticGraph()
64
+ # Only treat short ALL-CAPS words as acronyms if the text itself isn't shouting in ALL CAPS
65
+ text_has_lowercase = any(c.islower() for c in text)
66
+
67
+ for idx, match in enumerate(self._TOKEN_PATTERN.finditer(text)):
68
+ raw_token = match.group(0)
69
+ clean_token = raw_token.strip(".,!?:;\"'()[]{}-")
70
+ if not clean_token:
71
+ continue
72
+
73
+ start, end = match.span()
74
+ span = SourceSpan(start_char=start, end_char=end, text=raw_token)
75
+
76
+ has_digit = any(ch.isdigit() for ch in clean_token)
77
+ has_alpha = any(ch.isalpha() for ch in clean_token)
78
+
79
+ # 1. Numerical / Quantitative Invariants (pure numbers, currency, percentages, versions, times)
80
+ if has_digit and not has_alpha:
81
+ unit = None
82
+ if clean_token.startswith(("$", "€", "£", "₹")):
83
+ unit = clean_token[0]
84
+ elif clean_token.endswith("%"):
85
+ unit = "%"
86
+ node_id = f"num_{idx}"
87
+ graph.nodes[node_id] = NumericalInvariant(
88
+ id=node_id,
89
+ value=clean_token,
90
+ normalized_value=clean_token,
91
+ unit=unit,
92
+ source_span=span,
93
+ )
94
+
95
+ # 2. Mixed Alphanumeric Identifiers & Quantities (e.g., S3, AI302, 500mg, 15th)
96
+ elif has_digit and has_alpha:
97
+ if clean_token[0].isdigit():
98
+ node_id = f"num_{idx}"
99
+ graph.nodes[node_id] = NumericalInvariant(
100
+ id=node_id,
101
+ value=clean_token,
102
+ normalized_value=clean_token,
103
+ source_span=span,
104
+ )
105
+ else:
106
+ node_id = f"ent_{idx}"
107
+ graph.nodes[node_id] = Entity(
108
+ id=node_id,
109
+ value=clean_token,
110
+ normalized_value=clean_token,
111
+ source_span=span,
112
+ )
113
+
114
+ # 3. Structured Identifiers (e.g., emails or domain-like tokens containing '@')
115
+ elif "@" in clean_token:
116
+ node_id = f"ent_{idx}"
117
+ graph.nodes[node_id] = Entity(
118
+ id=node_id,
119
+ value=clean_token,
120
+ normalized_value=clean_token,
121
+ source_span=span,
122
+ )
123
+
124
+ # 4. Lexical Entities: Proper Nouns, CamelCase/PascalCase, and Acronyms
125
+ elif len(clean_token) >= 2:
126
+ is_camel_or_pascal = (
127
+ any(c.isupper() for c in clean_token[1:])
128
+ and any(c.islower() for c in clean_token)
129
+ )
130
+ is_capitalized_word = (
131
+ clean_token[0].isupper()
132
+ and clean_token[1:].islower()
133
+ and len(clean_token) > 2
134
+ )
135
+ is_acronym = (
136
+ text_has_lowercase
137
+ and clean_token.isupper()
138
+ and 2 <= len(clean_token) <= 5
139
+ )
140
+
141
+ if is_camel_or_pascal or is_capitalized_word or is_acronym:
142
+ node_id = f"ent_{idx}"
143
+ graph.nodes[node_id] = Entity(
144
+ id=node_id,
145
+ value=clean_token,
146
+ normalized_value=clean_token.lower(),
147
+ source_span=span,
148
+ )
149
+
150
+ return graph
151
+
152
+ def compile(self, text: str) -> SemanticGraph:
153
+ return self.extract_invariants(text)
154
+
155
+ def compress(self, text: str) -> CompressionResult:
156
+ original_tokens = len(text)
157
+ orig_hash = self._hash_text(text)
158
+
159
+ # 1. COMPILE
160
+ ir = self.compile(text)
161
+ inv_hash = self._hash_ir(ir)
162
+
163
+ # 2. GENERATE CANDIDATES
164
+ all_candidates = []
165
+ for comp in self.compressors:
166
+ if comp.can_handle(text, ir, self.config):
167
+ candidates = comp.generate_candidates(text, ir, self.config)
168
+ for cand in candidates:
169
+ all_candidates.append((comp.name, cand))
170
+
171
+ # 3. VERIFY
172
+ valid_candidates = []
173
+ costs = []
174
+ proofs = []
175
+
176
+ for comp_name, cand in all_candidates:
177
+ report = self.verifier.verify(ir, cand)
178
+ if report.passed:
179
+ valid_candidates.append(cand)
180
+ # 4. MEASURE COST using the specific compressor that generated the candidate
181
+ comp_instance = self._compressor_map[comp_name]
182
+ cost = comp_instance.estimate_cost(cand, self.config)
183
+ costs.append(cost)
184
+
185
+ proof = CompressionProof(
186
+ original_hash=orig_hash,
187
+ invariant_hash=inv_hash,
188
+ candidate_hash=self._hash_text(cand),
189
+ verified=True,
190
+ exact_reconstruction=(cand == text),
191
+ preservation_contract=self.config.mode,
192
+ preserved=len(report.preserved_invariants),
193
+ changed=len(report.changed_invariants),
194
+ warnings=report.warnings,
195
+ compressor_chain=[comp_name],
196
+ )
197
+ proofs.append(proof)
198
+
199
+ # FAIL-SAFE
200
+ if not valid_candidates:
201
+ return CompressionResult(
202
+ text=text,
203
+ original_tokens=original_tokens,
204
+ compressed_tokens=original_tokens,
205
+ token_reduction=0,
206
+ compression_ratio=1.0,
207
+ mode=self.config.mode,
208
+ representation="original",
209
+ proof=CompressionProof(
210
+ original_hash=orig_hash,
211
+ invariant_hash=inv_hash,
212
+ candidate_hash=orig_hash,
213
+ verified=True,
214
+ exact_reconstruction=True,
215
+ preservation_contract=self.config.mode,
216
+ preserved=len(ir.nodes),
217
+ changed=0,
218
+ ),
219
+ invariants=list(ir.nodes.values()),
220
+ warnings=["Fallback to original text"],
221
+ metadata={},
222
+ )
223
+
224
+ # 5. OPTIMIZE & SELECT
225
+ best_cand = self.optimizer.select_best(valid_candidates, costs)
226
+ best_idx = valid_candidates.index(best_cand)
227
+ best_proof = proofs[best_idx]
228
+
229
+ comp_tokens = len(best_cand)
230
+
231
+ # 6. RETURN
232
+ return CompressionResult(
233
+ text=best_cand,
234
+ original_tokens=original_tokens,
235
+ compressed_tokens=comp_tokens,
236
+ token_reduction=original_tokens - comp_tokens,
237
+ compression_ratio=original_tokens / comp_tokens if comp_tokens > 0 else 0.0,
238
+ mode=self.config.mode,
239
+ representation=best_proof.compressor_chain[0],
240
+ proof=best_proof,
241
+ invariants=list(ir.nodes.values()),
242
+ warnings=best_proof.warnings,
243
+ metadata={},
244
+ )
@@ -0,0 +1,19 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import Any, List, Optional
3
+ from ..config import InvariaConfig
4
+ from ..ir.models import SemanticGraph
5
+
6
+ class Compressor(ABC):
7
+ name: str
8
+
9
+ @abstractmethod
10
+ def can_handle(self, context: str, ir: SemanticGraph, config: InvariaConfig) -> bool:
11
+ pass
12
+
13
+ @abstractmethod
14
+ def generate_candidates(self, context: str, ir: SemanticGraph, config: InvariaConfig) -> List[str]:
15
+ pass
16
+
17
+ @abstractmethod
18
+ def estimate_cost(self, candidate: str, config: InvariaConfig) -> float:
19
+ pass
@@ -0,0 +1,31 @@
1
+ import re
2
+ from typing import List
3
+ from .base import Compressor
4
+ from ..config import InvariaConfig
5
+ from ..ir.models import SemanticGraph
6
+
7
+ class LexicalCompressor(Compressor):
8
+ name: str = "lexical"
9
+
10
+ def can_handle(self, context: str, ir: SemanticGraph, config: InvariaConfig) -> bool:
11
+ return True
12
+
13
+ def generate_candidates(self, context: str, ir: SemanticGraph, config: InvariaConfig) -> List[str]:
14
+ # Basic deterministic lexical transformations
15
+
16
+ # 1. Whitespace normalization
17
+ normalized = re.sub(r'\s+', ' ', context).strip()
18
+
19
+ # 2. Duplicate punctuation cleanup
20
+ cleaned = re.sub(r'([.?!,])\1+', r'\1', normalized)
21
+
22
+ candidates = [normalized]
23
+ if cleaned != normalized:
24
+ candidates.append(cleaned)
25
+
26
+ return candidates
27
+
28
+ def estimate_cost(self, candidate: str, config: InvariaConfig) -> float:
29
+ # Simple heuristic: length of string as a proxy for token cost
30
+ # In later phases, use actual tokenizer
31
+ return float(len(candidate))
@@ -0,0 +1,13 @@
1
+ from typing import Optional, Literal
2
+ from pydantic import BaseModel, Field
3
+
4
+ class InvariaConfig(BaseModel):
5
+ mode: Literal["semantic", "invariant", "reversible"] = "invariant"
6
+ provider: Optional[str] = None
7
+ model: Optional[str] = None
8
+ tokenizer: Optional[str] = None
9
+ verify: bool = True
10
+ logging_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = "INFO"
11
+
12
+ # Optimizer settings
13
+ target_tokens: Optional[int] = None
@@ -0,0 +1,47 @@
1
+ class InvariaError(Exception):
2
+ """Base exception for all Invaria errors."""
3
+ pass
4
+
5
+ class ParsingError(InvariaError):
6
+ """Raised when parsing context fails."""
7
+ pass
8
+
9
+ class UnsupportedContentError(InvariaError):
10
+ """Raised when content type is not supported."""
11
+ pass
12
+
13
+ class CompressionError(InvariaError):
14
+ """Raised when compression process fails."""
15
+ pass
16
+
17
+ class VerificationError(InvariaError):
18
+ """Raised when a candidate fails verification checks."""
19
+ pass
20
+
21
+ class InvariantViolation(VerificationError):
22
+ """Raised when a required invariant is violated."""
23
+ pass
24
+
25
+ class ReconstructionError(VerificationError):
26
+ """Raised when exact reversible reconstruction fails."""
27
+ pass
28
+
29
+ class ConfigurationError(InvariaError):
30
+ """Raised when configuration is invalid."""
31
+ pass
32
+
33
+ class ProviderError(InvariaError):
34
+ """Raised when interacting with an LLM provider fails."""
35
+ pass
36
+
37
+ class TokenizerError(InvariaError):
38
+ """Raised when tokenization fails."""
39
+ pass
40
+
41
+ class RenderingError(InvariaError):
42
+ """Raised when rendering a candidate fails."""
43
+ pass
44
+
45
+ class OptimizationError(InvariaError):
46
+ """Raised when the optimization engine fails to find a valid representation."""
47
+ pass
@@ -0,0 +1,53 @@
1
+ from typing import Any, Dict, List, Optional
2
+ from pydantic import BaseModel, Field
3
+
4
+ class SourceSpan(BaseModel):
5
+ start_char: int
6
+ end_char: int
7
+ text: str
8
+
9
+ class SemanticNode(BaseModel):
10
+ id: str
11
+ type: str
12
+ value: Any
13
+ normalized_value: Optional[Any] = None
14
+ source_span: Optional[SourceSpan] = None
15
+ confidence: float = 1.0
16
+ provenance: Optional[str] = None
17
+ metadata: Dict[str, Any] = Field(default_factory=dict)
18
+
19
+ class Entity(SemanticNode):
20
+ type: str = "entity"
21
+
22
+ class Fact(SemanticNode):
23
+ type: str = "fact"
24
+ subject: str
25
+ predicate: str
26
+ object: str
27
+
28
+ class Constraint(SemanticNode):
29
+ type: str = "constraint"
30
+ polarity: str = "positive" # "positive" or "negative"
31
+
32
+ class NumericalInvariant(SemanticNode):
33
+ type: str = "number"
34
+ unit: Optional[str] = None
35
+
36
+ class TemporalInvariant(SemanticNode):
37
+ type: str = "temporal"
38
+ relation: str = "at" # "before", "after", "at"
39
+
40
+ class Instruction(SemanticNode):
41
+ type: str = "instruction"
42
+ modality: str = "must" # "must", "should", "may", etc.
43
+
44
+ class GraphEdge(BaseModel):
45
+ source_id: str
46
+ target_id: str
47
+ relation: str
48
+ metadata: Dict[str, Any] = Field(default_factory=dict)
49
+
50
+ class SemanticGraph(BaseModel):
51
+ nodes: Dict[str, SemanticNode] = Field(default_factory=dict)
52
+ edges: List[GraphEdge] = Field(default_factory=list)
53
+ metadata: Dict[str, Any] = Field(default_factory=dict)
@@ -0,0 +1,14 @@
1
+ from typing import List, Tuple
2
+ from ..config import InvariaConfig
3
+
4
+ class Optimizer:
5
+ def __init__(self, config: InvariaConfig):
6
+ self.config = config
7
+
8
+ def select_best(self, valid_candidates: List[str], costs: List[float]) -> str:
9
+ if not valid_candidates:
10
+ raise ValueError("No valid candidates provided to the optimizer.")
11
+
12
+ # Simple greedy search: select the one with the lowest cost
13
+ best_idx = costs.index(min(costs))
14
+ return valid_candidates[best_idx]
@@ -0,0 +1,14 @@
1
+ from typing import List, Set
2
+ from pydantic import BaseModel, Field
3
+
4
+ class PreservationContract(BaseModel):
5
+ strictness: str = "strict"
6
+ required: Set[str] = Field(default_factory=lambda: {
7
+ "entities",
8
+ "facts",
9
+ "constraints",
10
+ "numbers",
11
+ "dates",
12
+ "instructions"
13
+ })
14
+ verification_level: str = "CRITICAL"
@@ -0,0 +1,23 @@
1
+ from typing import List, Any
2
+ from pydantic import BaseModel, Field
3
+
4
+ class VerificationReport(BaseModel):
5
+ passed: bool
6
+ critical_failures: List[str] = Field(default_factory=list)
7
+ warnings: List[str] = Field(default_factory=list)
8
+ preserved_invariants: List[Any] = Field(default_factory=list)
9
+ changed_invariants: List[Any] = Field(default_factory=list)
10
+ missing_invariants: List[Any] = Field(default_factory=list)
11
+ confidence: float = 1.0
12
+
13
+ class CompressionProof(BaseModel):
14
+ original_hash: str
15
+ invariant_hash: str
16
+ candidate_hash: str
17
+ verified: bool
18
+ exact_reconstruction: bool
19
+ preservation_contract: str
20
+ preserved: int
21
+ changed: int
22
+ warnings: List[str] = Field(default_factory=list)
23
+ compressor_chain: List[str] = Field(default_factory=list)
@@ -0,0 +1,40 @@
1
+ import re
2
+ from .report import VerificationReport
3
+ from .contract import PreservationContract
4
+ from ..ir.models import SemanticGraph
5
+
6
+
7
+ class VerificationEngine:
8
+ def __init__(self, contract: PreservationContract):
9
+ self.contract = contract
10
+
11
+ @staticmethod
12
+ def _contains_exact_token(text: str, token: str) -> bool:
13
+ escaped = re.escape(token)
14
+ # Ensure alphanumeric boundaries are respected so '15' doesn't match '1500'
15
+ prefix = r"(?<![A-Za-z0-9_])" if token[0].isalnum() else ""
16
+ suffix = r"(?![A-Za-z0-9_])" if token[-1].isalnum() else ""
17
+ pattern = f"{prefix}{escaped}{suffix}"
18
+ return re.search(pattern, text) is not None
19
+
20
+ def verify(self, original_ir: SemanticGraph, candidate_text: str) -> VerificationReport:
21
+ failures = []
22
+ preserved = []
23
+ missing = []
24
+
25
+ for node_id, node in original_ir.nodes.items():
26
+ val_str = str(node.value)
27
+ if self._contains_exact_token(candidate_text, val_str):
28
+ preserved.append(node)
29
+ else:
30
+ failures.append(f"Missing invariant ({node.type}): {val_str}")
31
+ missing.append(node)
32
+
33
+ passed = len(failures) == 0
34
+
35
+ return VerificationReport(
36
+ passed=passed,
37
+ critical_failures=failures,
38
+ preserved_invariants=preserved,
39
+ missing_invariants=missing,
40
+ )
@@ -0,0 +1,22 @@
1
+ from invaria import Invaria
2
+
3
+ def test_basic_compression():
4
+ compiler = Invaria(mode="invariant")
5
+ text = "This is a test. This is only a test."
6
+
7
+ result = compiler.compress(text)
8
+
9
+ assert result.proof.verified is True
10
+ # The lexical compressor should have cleaned up spaces
11
+ assert result.text == "This is a test. This is only a test."
12
+ assert result.compressed_tokens < result.original_tokens
13
+
14
+ def test_compile_api():
15
+ compiler = Invaria()
16
+ text = "PostgreSQL is a great database."
17
+ ir = compiler.compile(text)
18
+
19
+ # Should have extracted some naive entities (e.g., PostgreSQL)
20
+ assert len(ir.nodes) > 0
21
+ found_pg = any(node.value == "PostgreSQL" for node in ir.nodes.values())
22
+ assert found_pg is True