promptcapsule 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.
- promptcapsule-0.1.0/LICENSE +21 -0
- promptcapsule-0.1.0/PKG-INFO +609 -0
- promptcapsule-0.1.0/README.md +576 -0
- promptcapsule-0.1.0/promptcapsule/__init__.py +8 -0
- promptcapsule-0.1.0/promptcapsule/backends.py +195 -0
- promptcapsule-0.1.0/promptcapsule/core.py +197 -0
- promptcapsule-0.1.0/promptcapsule/integrity.py +41 -0
- promptcapsule-0.1.0/promptcapsule.egg-info/PKG-INFO +609 -0
- promptcapsule-0.1.0/promptcapsule.egg-info/SOURCES.txt +16 -0
- promptcapsule-0.1.0/promptcapsule.egg-info/dependency_links.txt +1 -0
- promptcapsule-0.1.0/promptcapsule.egg-info/requires.txt +12 -0
- promptcapsule-0.1.0/promptcapsule.egg-info/top_level.txt +1 -0
- promptcapsule-0.1.0/pyproject.toml +62 -0
- promptcapsule-0.1.0/setup.cfg +4 -0
- promptcapsule-0.1.0/tests/test_backends.py +118 -0
- promptcapsule-0.1.0/tests/test_core.py +367 -0
- promptcapsule-0.1.0/tests/test_integration.py +244 -0
- promptcapsule-0.1.0/tests/test_integrity.py +124 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Udaya Nirogi
|
|
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,609 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: promptcapsule
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Open-source prompt compression & retrieval library
|
|
5
|
+
Author-email: Udaya Nirogi <udaya@example.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/UdayaNirogi/promptcapsule
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/UdayaNirogi/promptcapsule/issues
|
|
9
|
+
Keywords: prompt,compression,retrieval,ai,llm
|
|
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.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Requires-Python: >=3.8
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
25
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
|
26
|
+
Requires-Dist: flake8>=6.0; extra == "dev"
|
|
27
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
28
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
|
29
|
+
Provides-Extra: vault
|
|
30
|
+
Requires-Dist: boto3>=1.26; extra == "vault"
|
|
31
|
+
Requires-Dist: pygithub>=1.59; extra == "vault"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# PromptCapsule 📦
|
|
35
|
+
|
|
36
|
+
> Open-source prompt compression & retrieval library that solves a real problem for developers and AI enthusiasts.
|
|
37
|
+
|
|
38
|
+
## Overview
|
|
39
|
+
|
|
40
|
+
**PromptCapsule** is a generic, reusable, open-source tool for compressing and reliably reconstructing LLM prompts. It bridges the gap between short-prompt compression and long-prompt storage, giving developers an honest, transparent way to share, version-control, and manage their AI prompts.
|
|
41
|
+
|
|
42
|
+
### The Problem
|
|
43
|
+
|
|
44
|
+
When people talk about "prompt compression," they usually mean two fundamentally different things:
|
|
45
|
+
|
|
46
|
+
| Type | What It Does | Trade-off |
|
|
47
|
+
|------|-------------|-----------|
|
|
48
|
+
| **Type 1: True Compression** | Mathematically limited to ~500-word prompts → 8 characters (lossless) | No external storage needed, but very limited scope |
|
|
49
|
+
| **Type 2: Key-Based Retrieval** | 2,000-word prompt → 8-character hash that reconstructs the original (from any device, any account) | Requires a storage backend, but solves the real problem |
|
|
50
|
+
|
|
51
|
+
**PromptCapsule** gives you **BOTH**, transparently and automatically.
|
|
52
|
+
|
|
53
|
+
### The Solution
|
|
54
|
+
|
|
55
|
+
PromptCapsule uses a **hybrid approach**:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
Short prompts (<500 chars):
|
|
59
|
+
INPUT PROMPT → ZLIB COMPRESS → BASE85 ENCODE → Portable capsule string
|
|
60
|
+
(self-contained, no storage needed)
|
|
61
|
+
|
|
62
|
+
Long prompts (>500 chars):
|
|
63
|
+
INPUT PROMPT → STORE IN VAULT (SQLite, GitHub Gist, S3) → Generate short hash key
|
|
64
|
+
(retrieves from configured backend)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Both modes are **automatic** — just compress once and the library picks the best strategy. Both are **verified** — checksums ensure byte-for-byte exact reconstruction.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Features
|
|
72
|
+
|
|
73
|
+
✨ **Hybrid Compression**
|
|
74
|
+
- Short prompts: Inline zlib + Base85 compression
|
|
75
|
+
- Long prompts: Vault storage with automatic fallback
|
|
76
|
+
- Automatic mode selection based on size
|
|
77
|
+
|
|
78
|
+
🔒 **Integrity Verification**
|
|
79
|
+
- SHA256 checksums for all capsules
|
|
80
|
+
- Byte-for-byte exact reconstruction guarantee
|
|
81
|
+
- Verification status in decompression results
|
|
82
|
+
|
|
83
|
+
🎯 **Honest Positioning**
|
|
84
|
+
- Transparent about what it actually does (capsule strings, not LLM output compression)
|
|
85
|
+
- Clear comparisons vs. existing tools (LLMLingua, LangChain Hub, gzip)
|
|
86
|
+
- No false claims of novelty
|
|
87
|
+
|
|
88
|
+
🌍 **Pluggable Backends**
|
|
89
|
+
- **In-Memory**: Great for testing and prototyping
|
|
90
|
+
- **SQLite**: Local storage, no external dependencies
|
|
91
|
+
- **GitHub Gist**: Cloud storage, version control friendly
|
|
92
|
+
- **AWS S3**: Enterprise-grade scalability (optional)
|
|
93
|
+
|
|
94
|
+
⚙️ **Python 3.8+**
|
|
95
|
+
- Pure Python, minimal dependencies
|
|
96
|
+
- Cross-platform compatible
|
|
97
|
+
- Type hints throughout
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Installation
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# Basic installation (includes in-memory and SQLite backends)
|
|
105
|
+
pip install promptcapsule
|
|
106
|
+
|
|
107
|
+
# With cloud storage support
|
|
108
|
+
pip install promptcapsule[vault]
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Requirements
|
|
112
|
+
- Python 3.8+
|
|
113
|
+
- No external dependencies for core functionality
|
|
114
|
+
- Optional: `boto3` for S3 backend, `PyGithub` for GitHub Gist backend
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## Quick Start
|
|
119
|
+
|
|
120
|
+
### Basic Usage (Short Prompts)
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
from promptcapsule import PromptCapsule
|
|
124
|
+
|
|
125
|
+
pc = PromptCapsule()
|
|
126
|
+
|
|
127
|
+
# Compress a prompt
|
|
128
|
+
prompt = "You are a helpful Python coding assistant."
|
|
129
|
+
capsule = pc.compress(prompt)
|
|
130
|
+
# capsule: "cap_i_a1b2c3d4_K*i0?5Z7....."
|
|
131
|
+
|
|
132
|
+
# Decompress anywhere, on any device/account
|
|
133
|
+
result = pc.decompress(capsule)
|
|
134
|
+
assert result.text == prompt
|
|
135
|
+
assert result.verified is True # Integrity verified ✓
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Long Prompts with Vault Backend
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from promptcapsule import PromptCapsule
|
|
142
|
+
from promptcapsule.backends import SQLiteBackend
|
|
143
|
+
|
|
144
|
+
pc = PromptCapsule()
|
|
145
|
+
vault = SQLiteBackend("prompts.db")
|
|
146
|
+
|
|
147
|
+
# Compress a long, carefully-crafted prompt
|
|
148
|
+
long_prompt = """
|
|
149
|
+
You are an expert in machine learning...
|
|
150
|
+
[2000+ characters of detailed context]
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
capsule = pc.compress(long_prompt, vault_backend=vault)
|
|
154
|
+
# capsule: "cap_v_a1b2c3d4_sql_20240921_120000_0001"
|
|
155
|
+
|
|
156
|
+
# Decompress later (data retrieves from SQLite)
|
|
157
|
+
result = pc.decompress(capsule, vault_backend=vault)
|
|
158
|
+
assert result.text == long_prompt
|
|
159
|
+
assert result.verified is True
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Real-World Scenario: Version-Controlling Prompts
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
import json
|
|
166
|
+
from promptcapsule import PromptCapsule
|
|
167
|
+
from promptcapsule.backends import SQLiteBackend
|
|
168
|
+
|
|
169
|
+
pc = PromptCapsule()
|
|
170
|
+
vault = SQLiteBackend("prompts.db")
|
|
171
|
+
|
|
172
|
+
# Iterate on your prompts over time
|
|
173
|
+
prompts_history = {
|
|
174
|
+
"v1.0": pc.compress(
|
|
175
|
+
"Generate a blog post about AI",
|
|
176
|
+
vault_backend=vault
|
|
177
|
+
),
|
|
178
|
+
"v1.1": pc.compress(
|
|
179
|
+
"Generate a blog post about AI, focused on practical applications",
|
|
180
|
+
vault_backend=vault
|
|
181
|
+
),
|
|
182
|
+
"v1.2": pc.compress(
|
|
183
|
+
"Generate a technical blog post about AI/ML, 2000+ words, with code examples",
|
|
184
|
+
vault_backend=vault
|
|
185
|
+
),
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
# Save to git
|
|
189
|
+
with open("prompts.json", "w") as f:
|
|
190
|
+
json.dump(prompts_history, f)
|
|
191
|
+
|
|
192
|
+
# Later (or different branch), retrieve and decompress
|
|
193
|
+
with open("prompts.json", "r") as f:
|
|
194
|
+
history = json.load(f)
|
|
195
|
+
|
|
196
|
+
for version, capsule in history.items():
|
|
197
|
+
result = pc.decompress(capsule, vault_backend=vault)
|
|
198
|
+
print(f"{version}: {result.text[:50]}...")
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## How It Works
|
|
204
|
+
|
|
205
|
+
### Inline Mode (Short Prompts)
|
|
206
|
+
|
|
207
|
+
1. **Compress**: `prompt` → zlib (level 9) → Base85 encode → capsule
|
|
208
|
+
2. **Format**: `cap_i_<8-char checksum>_<encoded data>`
|
|
209
|
+
3. **Verify**: Decompress → compare checksum prefix
|
|
210
|
+
4. **Result**: Portable, self-contained capsule string
|
|
211
|
+
|
|
212
|
+
**Example**:
|
|
213
|
+
```
|
|
214
|
+
Original: "Hello world!" (12 bytes)
|
|
215
|
+
Capsule: "cap_i_2f575c63_EZxgxD/'" (28 bytes)
|
|
216
|
+
Ratio: ~2.3x (expected for very short content)
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Vault Mode (Long Prompts)
|
|
220
|
+
|
|
221
|
+
1. **Store**: `prompt` → Save to backend (SQLite/Gist/S3) → Generate key
|
|
222
|
+
2. **Format**: `cap_v_<8-char checksum>_<backend key>`
|
|
223
|
+
3. **Retrieve**: On decompress → fetch from backend using key
|
|
224
|
+
4. **Verify**: Compare checksum prefix with retrieved content
|
|
225
|
+
|
|
226
|
+
**Example**:
|
|
227
|
+
```
|
|
228
|
+
Original: "You are a senior software architect..." (2,000 chars)
|
|
229
|
+
Capsule: "cap_v_a1b2c3d4_sql_20240921_120000_0001" (41 chars)
|
|
230
|
+
Ratio: ~48x compression (key is permanent pointer to vault)
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Automatic Mode Selection
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
pc = PromptCapsule()
|
|
237
|
+
|
|
238
|
+
# Anything ≤ 500 bytes uses inline
|
|
239
|
+
pc.compress("short prompt") # cap_i_...
|
|
240
|
+
|
|
241
|
+
# Anything > 500 bytes needs vault
|
|
242
|
+
pc.compress("A" * 600) # Error! Need vault_backend=
|
|
243
|
+
|
|
244
|
+
# With vault, auto-selects best mode
|
|
245
|
+
pc.compress("short prompt", vault_backend=backend) # Still cap_i_...
|
|
246
|
+
pc.compress("A" * 600, vault_backend=backend) # cap_v_...
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Backends
|
|
252
|
+
|
|
253
|
+
### In-Memory Backend
|
|
254
|
+
|
|
255
|
+
Perfect for testing and prototyping:
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from promptcapsule.backends import InMemoryBackend
|
|
259
|
+
|
|
260
|
+
backend = InMemoryBackend()
|
|
261
|
+
capsule = pc.compress("long prompt" * 100, vault_backend=backend)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### SQLite Backend
|
|
265
|
+
|
|
266
|
+
Local, file-based storage:
|
|
267
|
+
|
|
268
|
+
```python
|
|
269
|
+
from promptcapsule.backends import SQLiteBackend
|
|
270
|
+
|
|
271
|
+
backend = SQLiteBackend("prompts.db")
|
|
272
|
+
# Auto-creates schema, stores prompts locally
|
|
273
|
+
capsule = pc.compress("long prompt" * 100, vault_backend=backend)
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### GitHub Gist Backend
|
|
277
|
+
|
|
278
|
+
Cloud storage with version control:
|
|
279
|
+
|
|
280
|
+
```python
|
|
281
|
+
from promptcapsule.backends import GitHubGistBackend
|
|
282
|
+
|
|
283
|
+
backend = GitHubGistBackend(token="github_pat_...")
|
|
284
|
+
# Stores as private gist, returns gist ID
|
|
285
|
+
capsule = pc.compress("long prompt" * 100, vault_backend=backend)
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
Requires: `pip install promptcapsule[vault]`
|
|
289
|
+
|
|
290
|
+
### AWS S3 Backend
|
|
291
|
+
|
|
292
|
+
Enterprise-grade cloud storage:
|
|
293
|
+
|
|
294
|
+
```python
|
|
295
|
+
from promptcapsule.backends import S3Backend
|
|
296
|
+
|
|
297
|
+
backend = S3Backend(bucket="my-prompts", region="us-east-1")
|
|
298
|
+
# Stores in S3, returns S3 key
|
|
299
|
+
capsule = pc.compress("long prompt" * 100, vault_backend=backend)
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
Requires: `pip install promptcapsule[vault]`
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Command-Line Interface
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
# Compress a prompt
|
|
310
|
+
echo "Your prompt here" | promptcapsule compress
|
|
311
|
+
# Output: cap_i_a1b2c3d4_...
|
|
312
|
+
|
|
313
|
+
# Decompress a capsule
|
|
314
|
+
promptcapsule decompress "cap_i_a1b2c3d4_..."
|
|
315
|
+
# Output: Your prompt here
|
|
316
|
+
|
|
317
|
+
# With vault backend
|
|
318
|
+
promptcapsule compress --vault sqlite:prompts.db < prompt.txt
|
|
319
|
+
promptcapsule decompress --vault sqlite:prompts.db "cap_v_..."
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Comparison with Existing Tools
|
|
325
|
+
|
|
326
|
+
| Tool | What It Does | Strength | Limitation |
|
|
327
|
+
|------|-------------|----------|-----------|
|
|
328
|
+
| **LLMLingua** | Lossy semantic compression of prompts | High compression ratios | Approximate reconstruction, no exact guarantee |
|
|
329
|
+
| **LangChain Hub** | Cloud-hosted prompt template sharing | Easy sharing, versioning | Locked into LangChain ecosystem |
|
|
330
|
+
| **gzip/zlib directly** | General-purpose compression | Simple, standard | Can't store large prompts, no key-based retrieval |
|
|
331
|
+
| **PromptCapsule** | Hybrid lossless + vault-based retrieval | Exact reconstruction, honest, pluggable | Requires storage backend for long prompts |
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Use Cases
|
|
336
|
+
|
|
337
|
+
### 1️⃣ Share Prompts Across Accounts
|
|
338
|
+
Move carefully-crafted prompts between work and personal accounts without copy-pasting:
|
|
339
|
+
|
|
340
|
+
```python
|
|
341
|
+
capsule = pc.compress(my_favorite_prompt)
|
|
342
|
+
# Share via email, Slack, message, etc.
|
|
343
|
+
# Later, paste in personal account
|
|
344
|
+
result = pc.decompress(capsule)
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### 2️⃣ Version-Control Your Prompts
|
|
348
|
+
Keep prompts in git alongside your code:
|
|
349
|
+
|
|
350
|
+
```
|
|
351
|
+
prompts/
|
|
352
|
+
├── article-writer-v1.0.cap
|
|
353
|
+
├── article-writer-v1.1.cap
|
|
354
|
+
└── article-writer-v2.0.cap
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### 3️⃣ Portable Prompt Library
|
|
358
|
+
Share a repo of prompts that works on any machine, any account:
|
|
359
|
+
|
|
360
|
+
```python
|
|
361
|
+
prompts = load_capsule_library("prompts.json")
|
|
362
|
+
for name, capsule in prompts.items():
|
|
363
|
+
result = pc.decompress(capsule, vault_backend=my_vault)
|
|
364
|
+
print(f"{name}: {result.text}")
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### 4️⃣ Automated Prompt Management
|
|
368
|
+
Build CI/CD pipelines that validate and archive prompts:
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
# Compress before commit
|
|
372
|
+
for prompt_file in glob("*.txt"):
|
|
373
|
+
with open(prompt_file) as f:
|
|
374
|
+
prompt = f.read()
|
|
375
|
+
capsule = pc.compress(prompt, vault_backend=vault)
|
|
376
|
+
save_to_metadata(capsule)
|
|
377
|
+
|
|
378
|
+
# Retrieve during deployment
|
|
379
|
+
capsule = load_from_metadata()
|
|
380
|
+
prompt = pc.decompress(capsule, vault_backend=vault).text
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## API Reference
|
|
386
|
+
|
|
387
|
+
### `PromptCapsule` Class
|
|
388
|
+
|
|
389
|
+
```python
|
|
390
|
+
class PromptCapsule:
|
|
391
|
+
def compress(
|
|
392
|
+
self,
|
|
393
|
+
text: str,
|
|
394
|
+
vault_backend: Optional[VaultBackend] = None,
|
|
395
|
+
) -> str:
|
|
396
|
+
"""
|
|
397
|
+
Compress a prompt into a capsule string.
|
|
398
|
+
|
|
399
|
+
Args:
|
|
400
|
+
text: The prompt to compress
|
|
401
|
+
vault_backend: Backend for storing long prompts (required if > 500 bytes)
|
|
402
|
+
|
|
403
|
+
Returns:
|
|
404
|
+
Capsule string (starts with "cap_")
|
|
405
|
+
|
|
406
|
+
Raises:
|
|
407
|
+
ValueError: If text is empty or > 500 bytes without vault
|
|
408
|
+
TypeError: If text is not a string
|
|
409
|
+
"""
|
|
410
|
+
|
|
411
|
+
def decompress(
|
|
412
|
+
self,
|
|
413
|
+
capsule: str,
|
|
414
|
+
vault_backend: Optional[VaultBackend] = None,
|
|
415
|
+
) -> CapsuleResult:
|
|
416
|
+
"""
|
|
417
|
+
Decompress a capsule back to the original prompt.
|
|
418
|
+
|
|
419
|
+
Args:
|
|
420
|
+
capsule: The capsule string to decompress
|
|
421
|
+
vault_backend: Backend for retrieving long prompts
|
|
422
|
+
|
|
423
|
+
Returns:
|
|
424
|
+
CapsuleResult with:
|
|
425
|
+
- text: Original prompt
|
|
426
|
+
- verified: Integrity check passed
|
|
427
|
+
- mode: "inline" or "vault"
|
|
428
|
+
- checksum: SHA256 of original
|
|
429
|
+
- original_size: Bytes
|
|
430
|
+
- capsule_size: Bytes
|
|
431
|
+
|
|
432
|
+
Raises:
|
|
433
|
+
ValueError: If capsule format is invalid
|
|
434
|
+
KeyError: If vault key not found
|
|
435
|
+
"""
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### `CapsuleResult` Named Tuple
|
|
439
|
+
|
|
440
|
+
```python
|
|
441
|
+
class CapsuleResult(NamedTuple):
|
|
442
|
+
text: str # Original prompt
|
|
443
|
+
verified: bool # Checksum matched
|
|
444
|
+
mode: str # "inline" or "vault"
|
|
445
|
+
checksum: str # SHA256 hash
|
|
446
|
+
original_size: int # Bytes
|
|
447
|
+
capsule_size: int # Bytes
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### `VaultBackend` Abstract Class
|
|
451
|
+
|
|
452
|
+
Implement to create custom backends:
|
|
453
|
+
|
|
454
|
+
```python
|
|
455
|
+
class VaultBackend:
|
|
456
|
+
def store(self, text: str, checksum: str) -> str:
|
|
457
|
+
"""Store text, return a key."""
|
|
458
|
+
raise NotImplementedError
|
|
459
|
+
|
|
460
|
+
def retrieve(self, key: str) -> str:
|
|
461
|
+
"""Retrieve text by key."""
|
|
462
|
+
raise NotImplementedError
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
---
|
|
466
|
+
|
|
467
|
+
## Testing
|
|
468
|
+
|
|
469
|
+
Run the full regression test suite:
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
python run_tests.py
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
Expected output:
|
|
476
|
+
```
|
|
477
|
+
======================================================================
|
|
478
|
+
PromptCapsule - Regression Test Suite
|
|
479
|
+
======================================================================
|
|
480
|
+
|
|
481
|
+
Core Functionality Tests:
|
|
482
|
+
✓ Compress short prompt (inline mode)
|
|
483
|
+
✓ Reject empty strings
|
|
484
|
+
✓ Reject invalid types
|
|
485
|
+
[... 24 more tests ...]
|
|
486
|
+
|
|
487
|
+
Test Results: 27/27 passed
|
|
488
|
+
======================================================================
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## Architecture Notes
|
|
494
|
+
|
|
495
|
+
### Why This Design?
|
|
496
|
+
|
|
497
|
+
1. **Hybrid approach**: Best of both worlds — inline compression for portability, vault for scale
|
|
498
|
+
2. **Honest positioning**: We don't claim to be better than lossy compression at reducing LLM cost — we solve a different problem (portability + exact reconstruction)
|
|
499
|
+
3. **Pluggable backends**: Future-proof; use SQLite today, S3 tomorrow, custom backend next week
|
|
500
|
+
4. **Integrity by default**: Every capsule includes a checksum; verification is automatic
|
|
501
|
+
5. **Zero external dependencies** for core functionality — just zlib and base64, both stdlib
|
|
502
|
+
|
|
503
|
+
### Checksum Strategy
|
|
504
|
+
|
|
505
|
+
- Uses SHA256 (64 hex chars)
|
|
506
|
+
- Stores first 8 chars in capsule for quick verification
|
|
507
|
+
- Prevents accidental corruption detection
|
|
508
|
+
- Does **not** provide cryptographic authentication (future: optional HMAC signing)
|
|
509
|
+
|
|
510
|
+
### Compression Levels
|
|
511
|
+
|
|
512
|
+
- **Zlib level 9**: Maximum compression
|
|
513
|
+
- **Base85**: Better human readability than Base64 (4-char savings per 80 bytes)
|
|
514
|
+
- **Trade-off**: ~2-3x size increase for very short content (overhead of capsule format)
|
|
515
|
+
|
|
516
|
+
---
|
|
517
|
+
|
|
518
|
+
## Roadmap
|
|
519
|
+
|
|
520
|
+
- [ ] CLI tool with full feature parity
|
|
521
|
+
- [ ] HMAC signing for optional authentication
|
|
522
|
+
- [ ] Async backend support
|
|
523
|
+
- [ ] Compression format versioning (for future improvements)
|
|
524
|
+
- [ ] Web UI for managing vaults
|
|
525
|
+
- [ ] Prompt templates + variable interpolation
|
|
526
|
+
- [ ] Analytics: track prompt reuse, version adoption
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
## Security Considerations
|
|
531
|
+
|
|
532
|
+
- **Integrity**: ✅ Checksums detect corruption
|
|
533
|
+
- **Authenticity**: ⚠️ No signing (roadmap)
|
|
534
|
+
- **Confidentiality**: ⚠️ Vault contents transmitted/stored in plaintext (use HTTPS, encrypted S3, private gists)
|
|
535
|
+
- **Access Control**: Depends on backend (GitHub: private gists, S3: IAM policies)
|
|
536
|
+
|
|
537
|
+
**Recommendation**: Treat capsule strings like URLs — they're short but semantically empty. Don't rely on them for security-critical operations.
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## License
|
|
542
|
+
|
|
543
|
+
MIT License - see LICENSE file
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## Contributing
|
|
548
|
+
|
|
549
|
+
Contributions welcome! Please:
|
|
550
|
+
|
|
551
|
+
1. Write tests for new features
|
|
552
|
+
2. Follow PEP 8 style guide
|
|
553
|
+
3. Add docstrings
|
|
554
|
+
4. Update README with examples
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Citation
|
|
559
|
+
|
|
560
|
+
If you use PromptCapsule in your research or project, please cite:
|
|
561
|
+
|
|
562
|
+
```bibtex
|
|
563
|
+
@software{promptcapsule2024,
|
|
564
|
+
title={PromptCapsule: Open-source prompt compression and retrieval library},
|
|
565
|
+
author={Nirogi, Udaya},
|
|
566
|
+
year={2024},
|
|
567
|
+
url={https://github.com/UdayaNirogi/promptcapsule}
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
## FAQ
|
|
574
|
+
|
|
575
|
+
**Q: How is this different from just using a URL shortener?**
|
|
576
|
+
A: URL shorteners store data on a third-party server. PromptCapsule lets you choose your own backend (SQLite locally, S3 privately, GitHub Gist for sharing, etc.). Plus, checksums guarantee integrity.
|
|
577
|
+
|
|
578
|
+
**Q: Can I use this to compress LLM outputs?**
|
|
579
|
+
A: No — that's a different problem (lossy compression). PromptCapsule is for *inputs* (prompts), not outputs.
|
|
580
|
+
|
|
581
|
+
**Q: Is the capsule string secure?**
|
|
582
|
+
A: No — treat it like a URL. The 8-char checksum prefix is for integrity, not authentication. If you need signing, that's a roadmap item.
|
|
583
|
+
|
|
584
|
+
**Q: What about very old Python versions?**
|
|
585
|
+
A: We support Python 3.8+. Older versions should still work (no fancy syntax), but we don't test them.
|
|
586
|
+
|
|
587
|
+
**Q: Can I use multiple backends at once?**
|
|
588
|
+
A: Yes! Just pass different backends to different compress/decompress calls. Each backend is independent.
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## See Also
|
|
593
|
+
|
|
594
|
+
- [LLMLingua](https://github.com/microsoft/LLMLingua) — Lossy prompt compression
|
|
595
|
+
- [LangChain Hub](https://smith.langchain.com/) — Prompt management platform
|
|
596
|
+
- [zlib Documentation](https://www.zlib.net/) — Compression format
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## Feedback & Support
|
|
601
|
+
|
|
602
|
+
- 📖 [Documentation](https://github.com/UdayaNirogi/promptcapsule)
|
|
603
|
+
- 🐛 [Report Issues](https://github.com/UdayaNirogi/promptcapsule/issues)
|
|
604
|
+
- 💬 [Discussions](https://github.com/UdayaNirogi/promptcapsule/discussions)
|
|
605
|
+
- 📧 Email: udaya@example.com
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
**Made with ❤️ for developers who care about their prompts.**
|