llmpromptvault 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,23 @@
1
+ ```
2
+ MIT License
3
+
4
+ Copyright (c) 2025 Your Name
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
23
+ ```
@@ -0,0 +1,331 @@
1
+ Metadata-Version: 2.4
2
+ Name: llmpromptvault
3
+ Version: 0.1.0
4
+ Summary: Version, compare, and manage your LLM prompts. No API keys required. Bring your own model.
5
+ Author-email: Ankur Srivastav <ankursrivastava98@gmail.com>
6
+ License: MIT
7
+ Keywords: llm,prompts,prompt-engineering,prompt-management,versioning,mlops,ai,comparison,testing
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.9
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Software Development :: Version Control
19
+ Requires-Python: >=3.9
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: pyyaml>=6.0
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=7.0; extra == "dev"
25
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
26
+ Requires-Dist: black>=23.0; extra == "dev"
27
+ Requires-Dist: build; extra == "dev"
28
+ Requires-Dist: twine; extra == "dev"
29
+ Dynamic: license-file
30
+
31
+ # PromptVault 🔐
32
+
33
+ > **Version and compare your LLM prompts. No API key required. Bring your own model.**
34
+
35
+ [![PyPI version](https://badge.fury.io/py/promptvault.svg)](https://pypi.org/project/promptvault/)
36
+ [![Python](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
37
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
38
+
39
+ ---
40
+
41
+ ## What PromptVault Does
42
+
43
+ PromptVault is a **prompt management library** — not an LLM client. It does three things:
44
+
45
+ 1. **Versions your prompts** — tracks every change like Git
46
+ 2. **Logs responses** — stores what each prompt returned, with latency and token counts
47
+ 3. **Compares prompts** — shows you side-by-side how two prompt versions perform
48
+
49
+ **PromptVault never calls any LLM.** You call your own model however you like — OpenAI, Claude, Gemini, Ollama, a local model, anything. You pass the response to PromptVault and it handles the rest.
50
+
51
+ ---
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ pip install promptvault
57
+ ```
58
+
59
+ Only one dependency: `pyyaml`. Everything else uses Python's standard library.
60
+
61
+ ---
62
+
63
+ ## Quick Start
64
+
65
+ ```python
66
+ from promptvault import Prompt, Compare
67
+
68
+ # 1. Define two versions of a prompt
69
+ v1 = Prompt("summarize", template="Summarize this: {text}", version="v1")
70
+ v2 = Prompt("summarize", template="Summarize in 3 bullet points: {text}", version="v2")
71
+
72
+ # 2. YOU call your LLM (any model, any way you like)
73
+ r1 = your_llm(v1.render(text="Some article content..."))
74
+ r2 = your_llm(v2.render(text="Some article content..."))
75
+
76
+ # 3. PromptVault compares and logs them
77
+ cmp = Compare(v1, v2)
78
+ cmp.log(r1, r2)
79
+ cmp.show()
80
+ ```
81
+
82
+ Output:
83
+ ```
84
+ ────────────────────────────────────────────────────────────
85
+ PROMPTVAULT COMPARISON
86
+ ────────────────────────────────────────────────────────────
87
+ Prompt A summarize (v1)
88
+ Prompt B summarize (v2)
89
+ ────────────────────────────────────────────────────────────
90
+
91
+ ── Response A ──
92
+ Here is a summary of the article...
93
+
94
+ ── Response B ──
95
+ • Key point one
96
+ • Key point two
97
+ • Key point three
98
+
99
+ ────────────────────────────────────────────────────────────
100
+ Metric Prompt A Prompt B
101
+ ──────────────────────────── ──────────── ────────────
102
+ Word count 12 18
103
+ Char count 68 112
104
+ Latency (ms) 820.0 950.0
105
+ Tokens 45 62
106
+ ────────────────────────────────────────────────────────────
107
+ ```
108
+
109
+ ---
110
+
111
+ ## Core API
112
+
113
+ ### `Prompt` — Define and version your prompts
114
+
115
+ ```python
116
+ from promptvault import Prompt
117
+
118
+ # Create a prompt
119
+ p = Prompt(
120
+ name="classify",
121
+ template="Classify this text as positive or negative: {text}",
122
+ version="v1",
123
+ description="Sentiment classifier",
124
+ tags=["classify", "sentiment"],
125
+ )
126
+
127
+ # See required variables
128
+ p.variables() # ['text']
129
+
130
+ # Render it (just string formatting — no LLM call)
131
+ rendered = p.render(text="I love this product!")
132
+
133
+ # YOU call your LLM
134
+ response = your_llm(rendered)
135
+
136
+ # Log the response
137
+ p.log(
138
+ rendered_prompt=rendered,
139
+ response=response,
140
+ model="gpt-4o-mini", # optional
141
+ latency_ms=820, # optional
142
+ tokens=45, # optional
143
+ )
144
+
145
+ # View stats across all logged runs
146
+ p.stats()
147
+ # {
148
+ # 'run_count': 10,
149
+ # 'avg_latency_ms': 750.0,
150
+ # 'avg_tokens': 42.0,
151
+ # 'models_used': ['gpt-4o-mini'],
152
+ # ...
153
+ # }
154
+
155
+ # View raw run history
156
+ p.runs(last_n=10)
157
+ ```
158
+
159
+ ### Versioning
160
+
161
+ ```python
162
+ # Create v2 — v1 is automatically preserved in history
163
+ v2 = p.update(
164
+ new_template="You are a sentiment expert. Classify as positive/negative/neutral: {text}"
165
+ )
166
+ # Auto-increments: v1 → v2. Or pass version="my-version"
167
+
168
+ # See all versions
169
+ p.history() # [{'version': 'v1', 'template': ..., ...}, {'version': 'v2', ...}]
170
+ ```
171
+
172
+ ### Save & Load YAML
173
+
174
+ ```python
175
+ # Export to a human-readable file
176
+ p.save("prompts/classify.yaml")
177
+
178
+ # Load it back anywhere
179
+ p = Prompt.load("prompts/classify.yaml")
180
+ ```
181
+
182
+ ```yaml
183
+ # prompts/classify.yaml
184
+ name: classify
185
+ version: v1
186
+ description: Sentiment classifier
187
+ template: 'Classify this text as positive or negative: {text}'
188
+ tags:
189
+ - classify
190
+ - sentiment
191
+ ```
192
+
193
+ ---
194
+
195
+ ### `Compare` — Side-by-side prompt comparison
196
+
197
+ ```python
198
+ from promptvault import Compare
199
+
200
+ cmp = Compare(v1, v2)
201
+
202
+ # Log one comparison pair
203
+ cmp.log(
204
+ response_a=response_v1,
205
+ response_b=response_v2,
206
+ model="llama3", # optional
207
+ latency_ms_a=820, # optional
208
+ latency_ms_b=950, # optional
209
+ tokens_a=45, # optional
210
+ tokens_b=62, # optional
211
+ )
212
+
213
+ # Print side-by-side to terminal
214
+ cmp.show()
215
+
216
+ # Get structured diff dict
217
+ cmp.diff()
218
+ # {
219
+ # 'response_a': '...', 'response_b': '...',
220
+ # 'words_a': 12, 'words_b': 18,
221
+ # 'latency_ms_a': 820, 'latency_ms_b': 950,
222
+ # ...
223
+ # }
224
+
225
+ # Aggregate summary across multiple comparison runs
226
+ cmp.summary()
227
+ # {
228
+ # 'total_comparisons': 5,
229
+ # 'avg_words_a': 12.0, 'avg_words_b': 18.2,
230
+ # 'avg_latency_ms_a': 810.0, 'avg_latency_ms_b': 940.0,
231
+ # ...
232
+ # }
233
+ ```
234
+
235
+ ---
236
+
237
+ ### `Registry` — Share prompts with your team
238
+
239
+ ```python
240
+ from promptvault import Registry
241
+
242
+ reg = Registry("./shared_prompts") # any folder path
243
+
244
+ # Push prompts in
245
+ reg.push(v1)
246
+ reg.push(v2)
247
+
248
+ # Pull them out anywhere
249
+ p = reg.pull("classify") # latest version
250
+ p = reg.pull("classify", "v1") # specific version
251
+
252
+ reg.list() # ['classify', 'summarize', ...]
253
+ reg.versions("classify") # ['v1', 'v2']
254
+ reg.delete("classify", "v1")
255
+ ```
256
+
257
+ ---
258
+
259
+ ## Works with Any LLM
260
+
261
+ Because PromptVault never makes LLM calls itself, it works with literally any model:
262
+
263
+ ```python
264
+ # OpenAI
265
+ import openai
266
+ client = openai.OpenAI(api_key="...")
267
+ response = client.chat.completions.create(model="gpt-4o", messages=[{"role": "user", "content": rendered}])
268
+ p.log(rendered, response.choices[0].message.content, model="gpt-4o")
269
+
270
+ # Anthropic
271
+ import anthropic
272
+ client = anthropic.Anthropic(api_key="...")
273
+ response = client.messages.create(model="claude-haiku-4-5-20251001", max_tokens=1024, messages=[{"role": "user", "content": rendered}])
274
+ p.log(rendered, response.content[0].text, model="claude-haiku-4-5-20251001")
275
+
276
+ # Ollama (local, free, no key)
277
+ import requests
278
+ response = requests.post("http://localhost:11434/api/generate", json={"model": "llama3", "prompt": rendered, "stream": False})
279
+ p.log(rendered, response.json()["response"], model="llama3")
280
+
281
+ # Any other LLM, API, or local model
282
+ response = any_llm_you_want(rendered)
283
+ p.log(rendered, response)
284
+ ```
285
+
286
+ ---
287
+
288
+ ## File Structure
289
+
290
+ ```
291
+ your_project/
292
+ ├── prompts/
293
+ │ └── classify.yaml ← exported prompt templates
294
+ ├── .promptvault/
295
+ │ ├── history.json ← version history
296
+ │ └── runs.db ← run logs (SQLite)
297
+ └── main.py
298
+ ```
299
+
300
+ Add `.promptvault/` to `.gitignore` to keep run logs local, or commit it to share analytics with your team.
301
+
302
+ ---
303
+
304
+ ## Run the Demo
305
+
306
+ ```bash
307
+ git clone https://github.com/your-username/promptvault
308
+ cd promptvault
309
+ pip install pyyaml
310
+ python examples/demo.py
311
+ ```
312
+
313
+ No API key needed — the demo uses simulated responses.
314
+
315
+ ---
316
+
317
+ ## Publish to PyPI
318
+
319
+ ```bash
320
+ pip install build twine
321
+ python -m build
322
+ twine upload dist/*
323
+ ```
324
+
325
+ See `PUBLISHING_GUIDE.md` for the full step-by-step.
326
+
327
+ ---
328
+
329
+ ## License
330
+
331
+ MIT © PromptVault Contributors
@@ -0,0 +1,301 @@
1
+ # PromptVault 🔐
2
+
3
+ > **Version and compare your LLM prompts. No API key required. Bring your own model.**
4
+
5
+ [![PyPI version](https://badge.fury.io/py/promptvault.svg)](https://pypi.org/project/promptvault/)
6
+ [![Python](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8
+
9
+ ---
10
+
11
+ ## What PromptVault Does
12
+
13
+ PromptVault is a **prompt management library** — not an LLM client. It does three things:
14
+
15
+ 1. **Versions your prompts** — tracks every change like Git
16
+ 2. **Logs responses** — stores what each prompt returned, with latency and token counts
17
+ 3. **Compares prompts** — shows you side-by-side how two prompt versions perform
18
+
19
+ **PromptVault never calls any LLM.** You call your own model however you like — OpenAI, Claude, Gemini, Ollama, a local model, anything. You pass the response to PromptVault and it handles the rest.
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ pip install promptvault
27
+ ```
28
+
29
+ Only one dependency: `pyyaml`. Everything else uses Python's standard library.
30
+
31
+ ---
32
+
33
+ ## Quick Start
34
+
35
+ ```python
36
+ from promptvault import Prompt, Compare
37
+
38
+ # 1. Define two versions of a prompt
39
+ v1 = Prompt("summarize", template="Summarize this: {text}", version="v1")
40
+ v2 = Prompt("summarize", template="Summarize in 3 bullet points: {text}", version="v2")
41
+
42
+ # 2. YOU call your LLM (any model, any way you like)
43
+ r1 = your_llm(v1.render(text="Some article content..."))
44
+ r2 = your_llm(v2.render(text="Some article content..."))
45
+
46
+ # 3. PromptVault compares and logs them
47
+ cmp = Compare(v1, v2)
48
+ cmp.log(r1, r2)
49
+ cmp.show()
50
+ ```
51
+
52
+ Output:
53
+ ```
54
+ ────────────────────────────────────────────────────────────
55
+ PROMPTVAULT COMPARISON
56
+ ────────────────────────────────────────────────────────────
57
+ Prompt A summarize (v1)
58
+ Prompt B summarize (v2)
59
+ ────────────────────────────────────────────────────────────
60
+
61
+ ── Response A ──
62
+ Here is a summary of the article...
63
+
64
+ ── Response B ──
65
+ • Key point one
66
+ • Key point two
67
+ • Key point three
68
+
69
+ ────────────────────────────────────────────────────────────
70
+ Metric Prompt A Prompt B
71
+ ──────────────────────────── ──────────── ────────────
72
+ Word count 12 18
73
+ Char count 68 112
74
+ Latency (ms) 820.0 950.0
75
+ Tokens 45 62
76
+ ────────────────────────────────────────────────────────────
77
+ ```
78
+
79
+ ---
80
+
81
+ ## Core API
82
+
83
+ ### `Prompt` — Define and version your prompts
84
+
85
+ ```python
86
+ from promptvault import Prompt
87
+
88
+ # Create a prompt
89
+ p = Prompt(
90
+ name="classify",
91
+ template="Classify this text as positive or negative: {text}",
92
+ version="v1",
93
+ description="Sentiment classifier",
94
+ tags=["classify", "sentiment"],
95
+ )
96
+
97
+ # See required variables
98
+ p.variables() # ['text']
99
+
100
+ # Render it (just string formatting — no LLM call)
101
+ rendered = p.render(text="I love this product!")
102
+
103
+ # YOU call your LLM
104
+ response = your_llm(rendered)
105
+
106
+ # Log the response
107
+ p.log(
108
+ rendered_prompt=rendered,
109
+ response=response,
110
+ model="gpt-4o-mini", # optional
111
+ latency_ms=820, # optional
112
+ tokens=45, # optional
113
+ )
114
+
115
+ # View stats across all logged runs
116
+ p.stats()
117
+ # {
118
+ # 'run_count': 10,
119
+ # 'avg_latency_ms': 750.0,
120
+ # 'avg_tokens': 42.0,
121
+ # 'models_used': ['gpt-4o-mini'],
122
+ # ...
123
+ # }
124
+
125
+ # View raw run history
126
+ p.runs(last_n=10)
127
+ ```
128
+
129
+ ### Versioning
130
+
131
+ ```python
132
+ # Create v2 — v1 is automatically preserved in history
133
+ v2 = p.update(
134
+ new_template="You are a sentiment expert. Classify as positive/negative/neutral: {text}"
135
+ )
136
+ # Auto-increments: v1 → v2. Or pass version="my-version"
137
+
138
+ # See all versions
139
+ p.history() # [{'version': 'v1', 'template': ..., ...}, {'version': 'v2', ...}]
140
+ ```
141
+
142
+ ### Save & Load YAML
143
+
144
+ ```python
145
+ # Export to a human-readable file
146
+ p.save("prompts/classify.yaml")
147
+
148
+ # Load it back anywhere
149
+ p = Prompt.load("prompts/classify.yaml")
150
+ ```
151
+
152
+ ```yaml
153
+ # prompts/classify.yaml
154
+ name: classify
155
+ version: v1
156
+ description: Sentiment classifier
157
+ template: 'Classify this text as positive or negative: {text}'
158
+ tags:
159
+ - classify
160
+ - sentiment
161
+ ```
162
+
163
+ ---
164
+
165
+ ### `Compare` — Side-by-side prompt comparison
166
+
167
+ ```python
168
+ from promptvault import Compare
169
+
170
+ cmp = Compare(v1, v2)
171
+
172
+ # Log one comparison pair
173
+ cmp.log(
174
+ response_a=response_v1,
175
+ response_b=response_v2,
176
+ model="llama3", # optional
177
+ latency_ms_a=820, # optional
178
+ latency_ms_b=950, # optional
179
+ tokens_a=45, # optional
180
+ tokens_b=62, # optional
181
+ )
182
+
183
+ # Print side-by-side to terminal
184
+ cmp.show()
185
+
186
+ # Get structured diff dict
187
+ cmp.diff()
188
+ # {
189
+ # 'response_a': '...', 'response_b': '...',
190
+ # 'words_a': 12, 'words_b': 18,
191
+ # 'latency_ms_a': 820, 'latency_ms_b': 950,
192
+ # ...
193
+ # }
194
+
195
+ # Aggregate summary across multiple comparison runs
196
+ cmp.summary()
197
+ # {
198
+ # 'total_comparisons': 5,
199
+ # 'avg_words_a': 12.0, 'avg_words_b': 18.2,
200
+ # 'avg_latency_ms_a': 810.0, 'avg_latency_ms_b': 940.0,
201
+ # ...
202
+ # }
203
+ ```
204
+
205
+ ---
206
+
207
+ ### `Registry` — Share prompts with your team
208
+
209
+ ```python
210
+ from promptvault import Registry
211
+
212
+ reg = Registry("./shared_prompts") # any folder path
213
+
214
+ # Push prompts in
215
+ reg.push(v1)
216
+ reg.push(v2)
217
+
218
+ # Pull them out anywhere
219
+ p = reg.pull("classify") # latest version
220
+ p = reg.pull("classify", "v1") # specific version
221
+
222
+ reg.list() # ['classify', 'summarize', ...]
223
+ reg.versions("classify") # ['v1', 'v2']
224
+ reg.delete("classify", "v1")
225
+ ```
226
+
227
+ ---
228
+
229
+ ## Works with Any LLM
230
+
231
+ Because PromptVault never makes LLM calls itself, it works with literally any model:
232
+
233
+ ```python
234
+ # OpenAI
235
+ import openai
236
+ client = openai.OpenAI(api_key="...")
237
+ response = client.chat.completions.create(model="gpt-4o", messages=[{"role": "user", "content": rendered}])
238
+ p.log(rendered, response.choices[0].message.content, model="gpt-4o")
239
+
240
+ # Anthropic
241
+ import anthropic
242
+ client = anthropic.Anthropic(api_key="...")
243
+ response = client.messages.create(model="claude-haiku-4-5-20251001", max_tokens=1024, messages=[{"role": "user", "content": rendered}])
244
+ p.log(rendered, response.content[0].text, model="claude-haiku-4-5-20251001")
245
+
246
+ # Ollama (local, free, no key)
247
+ import requests
248
+ response = requests.post("http://localhost:11434/api/generate", json={"model": "llama3", "prompt": rendered, "stream": False})
249
+ p.log(rendered, response.json()["response"], model="llama3")
250
+
251
+ # Any other LLM, API, or local model
252
+ response = any_llm_you_want(rendered)
253
+ p.log(rendered, response)
254
+ ```
255
+
256
+ ---
257
+
258
+ ## File Structure
259
+
260
+ ```
261
+ your_project/
262
+ ├── prompts/
263
+ │ └── classify.yaml ← exported prompt templates
264
+ ├── .promptvault/
265
+ │ ├── history.json ← version history
266
+ │ └── runs.db ← run logs (SQLite)
267
+ └── main.py
268
+ ```
269
+
270
+ Add `.promptvault/` to `.gitignore` to keep run logs local, or commit it to share analytics with your team.
271
+
272
+ ---
273
+
274
+ ## Run the Demo
275
+
276
+ ```bash
277
+ git clone https://github.com/your-username/promptvault
278
+ cd promptvault
279
+ pip install pyyaml
280
+ python examples/demo.py
281
+ ```
282
+
283
+ No API key needed — the demo uses simulated responses.
284
+
285
+ ---
286
+
287
+ ## Publish to PyPI
288
+
289
+ ```bash
290
+ pip install build twine
291
+ python -m build
292
+ twine upload dist/*
293
+ ```
294
+
295
+ See `PUBLISHING_GUIDE.md` for the full step-by-step.
296
+
297
+ ---
298
+
299
+ ## License
300
+
301
+ MIT © PromptVault Contributors
@@ -0,0 +1,37 @@
1
+ """
2
+ PromptVault — Version, compare, and manage your LLM prompts.
3
+
4
+ No API keys. No LLM calls. Bring your own model.
5
+
6
+ Quick Start:
7
+ from promptvault import Prompt, Compare
8
+
9
+ # 1. Define two prompt versions
10
+ v1 = Prompt("summarize", template="Summarize this: {text}")
11
+ v2 = Prompt("summarize", template="Summarize in 3 bullets: {text}", version="v2")
12
+
13
+ # 2. YOU call your LLM (any LLM, any way you like)
14
+ r1 = your_llm(v1.render(text="Some article..."))
15
+ r2 = your_llm(v2.render(text="Some article..."))
16
+
17
+ # 3. PromptVault compares and tracks
18
+ cmp = Compare(v1, v2)
19
+ cmp.log(r1, r2)
20
+ cmp.show()
21
+ """
22
+
23
+ from .prompt import Prompt
24
+ from .compare import Compare
25
+ from .registry import Registry
26
+ from .storage import PromptStorage
27
+
28
+ __version__ = "0.1.0"
29
+ __author__ = "PromptVault Contributors"
30
+ __license__ = "MIT"
31
+
32
+ __all__ = [
33
+ "Prompt",
34
+ "Compare",
35
+ "Registry",
36
+ "PromptStorage",
37
+ ]