instructvault 0.2.8__tar.gz → 0.3.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.
- instructvault-0.3.0/.gitignore +17 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/PKG-INFO +17 -1
- {instructvault-0.2.8 → instructvault-0.3.0}/README.md +15 -0
- instructvault-0.3.0/docs/assets/logo.png +0 -0
- instructvault-0.3.0/docs/audit_logging.md +25 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/cookbooks.md +39 -0
- instructvault-0.3.0/docs/spec.md +40 -0
- instructvault-0.3.0/examples/notebooks/instructvault_colab.ipynb +128 -0
- instructvault-0.3.0/examples/notebooks/instructvault_openai_colab.ipynb +112 -0
- instructvault-0.3.0/examples/notebooks/instructvault_rag_colab.ipynb +127 -0
- instructvault-0.3.0/examples/policies/policy_example.py +14 -0
- instructvault-0.3.0/examples/policies/policy_pack.py +26 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/pyproject.toml +2 -1
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/cli.py +53 -8
- instructvault-0.3.0/src/instructvault/eval.py +80 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/io.py +9 -0
- instructvault-0.3.0/src/instructvault/policy.py +33 -0
- instructvault-0.3.0/src/instructvault/render.py +57 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/sdk.py +3 -3
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/spec.py +4 -1
- {instructvault-0.2.8 → instructvault-0.3.0}/tests/test_cli_basic.py +34 -0
- instructvault-0.3.0/tests/test_eval_asserts.py +28 -0
- instructvault-0.2.8/src/instructvault/eval.py +0 -53
- instructvault-0.2.8/src/instructvault/render.py +0 -22
- {instructvault-0.2.8 → instructvault-0.3.0}/.github/CODEOWNERS +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/.github/pull_request_template.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/.github/workflows/ci.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/.github/workflows/prompt-checks.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/.github/workflows/release.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/CHANGELOG.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/CODE_OF_CONDUCT.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/CONTRIBUTING.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/LICENSE +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/SECURITY.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/assets/logo.svg +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/assets/logo_dark.png +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/assets/logo_dark.svg +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/assets/logo_light.svg +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/assets/playground.png +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/ci.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/ci_templates/Jenkinsfile +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/ci_templates/gitlab-ci.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/dropin_guide.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/governance.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/playground.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/release_checklist.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/templates/CODEOWNERS +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/docs/vision.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/datasets/classifier_cases.jsonl +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/datasets/rag_agent_cases.jsonl +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/datasets/rag_answer_cases.jsonl +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/datasets/support_cases.jsonl +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/prompts/classifier.prompt.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/prompts/guardrail.prompt.json +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/prompts/hello_world.prompt.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/prompts/rag_agent.prompt.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/prompts/rag_answer.prompt.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/examples/prompts/support_reply.prompt.yml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/README.md +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/ivault_playground/__init__.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/ivault_playground/app.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/ivault_playground/routes/api.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/ivault_playground/routes/ui.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/ivault_playground/static/app.css +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/ivault_playground/static/app.js +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/ivault_playground/templates/index.html +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/playground/pyproject.toml +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/__init__.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/bundle.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/diff.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/junit.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/scaffold.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/src/instructvault/store.py +0 -0
- {instructvault-0.2.8 → instructvault-0.3.0}/tests/test_playground_api.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: instructvault
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: Git-first prompt registry + CI evals + lightweight runtime SDK (ivault).
|
|
5
5
|
Project-URL: Homepage, https://github.com/05satyam/instruct_vault
|
|
6
6
|
Project-URL: Repository, https://github.com/05satyam/instruct_vault
|
|
@@ -9,6 +9,7 @@ License: Apache-2.0
|
|
|
9
9
|
License-File: LICENSE
|
|
10
10
|
Requires-Python: >=3.10
|
|
11
11
|
Requires-Dist: jinja2>=3.1
|
|
12
|
+
Requires-Dist: jsonschema>=4.21
|
|
12
13
|
Requires-Dist: pydantic>=2.7
|
|
13
14
|
Requires-Dist: pyyaml>=6.0
|
|
14
15
|
Requires-Dist: rich>=13.7
|
|
@@ -127,6 +128,10 @@ ivault validate prompts
|
|
|
127
128
|
ivault render prompts/support_reply.prompt.yml --vars '{"ticket_text":"My app crashed.","customer_name":"Sam"}'
|
|
128
129
|
```
|
|
129
130
|
|
|
131
|
+
Safety tip: add `--safe` to scan rendered output for common secret patterns.
|
|
132
|
+
Use `--strict-vars` to forbid unknown vars and `--redact` to mask detected secrets.
|
|
133
|
+
Use `--policy /path/to/policy.py` to enforce custom compliance rules.
|
|
134
|
+
|
|
130
135
|
### 4) Add dataset‑driven eval
|
|
131
136
|
`datasets/support_cases.jsonl`
|
|
132
137
|
```jsonl
|
|
@@ -142,6 +147,11 @@ Note: Prompts must include at least one inline test. Datasets are optional.
|
|
|
142
147
|
Migration tip: if you need to render a prompt that doesn’t yet include tests, use
|
|
143
148
|
`ivault render --allow-no-tests` or add a minimal test first.
|
|
144
149
|
|
|
150
|
+
Spec migration check:
|
|
151
|
+
```bash
|
|
152
|
+
ivault migrate prompts
|
|
153
|
+
```
|
|
154
|
+
|
|
145
155
|
### 5) Version prompts with tags
|
|
146
156
|
```bash
|
|
147
157
|
git add prompts datasets
|
|
@@ -179,6 +189,10 @@ vault = InstructVault(bundle_path="out/ivault.bundle.json")
|
|
|
179
189
|
- `examples/notebooks/instructvault_openai_colab.ipynb`
|
|
180
190
|
[](https://colab.research.google.com/github/05satyam/instruct_vault/blob/main/examples/notebooks/instructvault_openai_colab.ipynb)
|
|
181
191
|
|
|
192
|
+
## Example Policies
|
|
193
|
+
- `examples/policies/policy_example.py`
|
|
194
|
+
- `examples/policies/policy_pack.py`
|
|
195
|
+
|
|
182
196
|
## How teams use this in production
|
|
183
197
|
1) Prompt changes go through PRs
|
|
184
198
|
2) CI runs `validate` + `eval`
|
|
@@ -208,11 +222,13 @@ Then send `x-ivault-api-key` in requests (or keep it behind your org gateway).
|
|
|
208
222
|
If you don’t set the env var, no auth is required.
|
|
209
223
|
|
|
210
224
|
## Docs
|
|
225
|
+
- `docs/spec.md`
|
|
211
226
|
- `docs/vision.md`
|
|
212
227
|
- `docs/governance.md`
|
|
213
228
|
- `docs/ci.md`
|
|
214
229
|
- `docs/playground.md`
|
|
215
230
|
- `docs/cookbooks.md`
|
|
231
|
+
- `docs/audit_logging.md`
|
|
216
232
|
- `docs/dropin_guide.md`
|
|
217
233
|
- `docs/release_checklist.md`
|
|
218
234
|
- `docs/ci_templates/gitlab-ci.yml`
|
|
@@ -102,6 +102,10 @@ ivault validate prompts
|
|
|
102
102
|
ivault render prompts/support_reply.prompt.yml --vars '{"ticket_text":"My app crashed.","customer_name":"Sam"}'
|
|
103
103
|
```
|
|
104
104
|
|
|
105
|
+
Safety tip: add `--safe` to scan rendered output for common secret patterns.
|
|
106
|
+
Use `--strict-vars` to forbid unknown vars and `--redact` to mask detected secrets.
|
|
107
|
+
Use `--policy /path/to/policy.py` to enforce custom compliance rules.
|
|
108
|
+
|
|
105
109
|
### 4) Add dataset‑driven eval
|
|
106
110
|
`datasets/support_cases.jsonl`
|
|
107
111
|
```jsonl
|
|
@@ -117,6 +121,11 @@ Note: Prompts must include at least one inline test. Datasets are optional.
|
|
|
117
121
|
Migration tip: if you need to render a prompt that doesn’t yet include tests, use
|
|
118
122
|
`ivault render --allow-no-tests` or add a minimal test first.
|
|
119
123
|
|
|
124
|
+
Spec migration check:
|
|
125
|
+
```bash
|
|
126
|
+
ivault migrate prompts
|
|
127
|
+
```
|
|
128
|
+
|
|
120
129
|
### 5) Version prompts with tags
|
|
121
130
|
```bash
|
|
122
131
|
git add prompts datasets
|
|
@@ -154,6 +163,10 @@ vault = InstructVault(bundle_path="out/ivault.bundle.json")
|
|
|
154
163
|
- `examples/notebooks/instructvault_openai_colab.ipynb`
|
|
155
164
|
[](https://colab.research.google.com/github/05satyam/instruct_vault/blob/main/examples/notebooks/instructvault_openai_colab.ipynb)
|
|
156
165
|
|
|
166
|
+
## Example Policies
|
|
167
|
+
- `examples/policies/policy_example.py`
|
|
168
|
+
- `examples/policies/policy_pack.py`
|
|
169
|
+
|
|
157
170
|
## How teams use this in production
|
|
158
171
|
1) Prompt changes go through PRs
|
|
159
172
|
2) CI runs `validate` + `eval`
|
|
@@ -183,11 +196,13 @@ Then send `x-ivault-api-key` in requests (or keep it behind your org gateway).
|
|
|
183
196
|
If you don’t set the env var, no auth is required.
|
|
184
197
|
|
|
185
198
|
## Docs
|
|
199
|
+
- `docs/spec.md`
|
|
186
200
|
- `docs/vision.md`
|
|
187
201
|
- `docs/governance.md`
|
|
188
202
|
- `docs/ci.md`
|
|
189
203
|
- `docs/playground.md`
|
|
190
204
|
- `docs/cookbooks.md`
|
|
205
|
+
- `docs/audit_logging.md`
|
|
191
206
|
- `docs/dropin_guide.md`
|
|
192
207
|
- `docs/release_checklist.md`
|
|
193
208
|
- `docs/ci_templates/gitlab-ci.yml`
|
|
Binary file
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Audit Logging (recommended)
|
|
2
|
+
|
|
3
|
+
Log these fields for every render/eval execution:
|
|
4
|
+
- prompt path
|
|
5
|
+
- git ref or SHA
|
|
6
|
+
- spec_version
|
|
7
|
+
- dataset path (if any)
|
|
8
|
+
- policy module (if any)
|
|
9
|
+
- safe / strict-vars / redact flags
|
|
10
|
+
- timestamp
|
|
11
|
+
|
|
12
|
+
Example payload:
|
|
13
|
+
```
|
|
14
|
+
{
|
|
15
|
+
"prompt": "prompts/support_reply.prompt.yml",
|
|
16
|
+
"ref": "prompts/v1.2.0",
|
|
17
|
+
"spec_version": "1.0",
|
|
18
|
+
"dataset": "datasets/support_cases.jsonl",
|
|
19
|
+
"policy": "docs/policy_pack.py",
|
|
20
|
+
"safe": true,
|
|
21
|
+
"strict_vars": true,
|
|
22
|
+
"redact": true,
|
|
23
|
+
"timestamp": "2026-02-02T12:00:00Z"
|
|
24
|
+
}
|
|
25
|
+
```
|
|
@@ -133,3 +133,42 @@ GitHub Actions snippet:
|
|
|
133
133
|
Notes:
|
|
134
134
|
- The dataset is still local when `ivault` runs.
|
|
135
135
|
- Keep dataset files versioned or checksum-locked for reproducibility.
|
|
136
|
+
|
|
137
|
+
## 12) Policy hooks (compliance / PII)
|
|
138
|
+
Create a policy module and pass it to `ivault`:
|
|
139
|
+
```bash
|
|
140
|
+
ivault validate prompts --policy examples/policies/policy_example.py
|
|
141
|
+
ivault eval prompts/support_reply.prompt.yml --policy examples/policies/policy_example.py
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Default policy pack (simple PII + forbidden phrases):
|
|
145
|
+
```bash
|
|
146
|
+
ivault validate prompts --policy examples/policies/policy_pack.py
|
|
147
|
+
ivault eval prompts/support_reply.prompt.yml --policy examples/policies/policy_pack.py
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 13) Custom evals (your own rules)
|
|
151
|
+
You can run your own checks using the SDK:
|
|
152
|
+
```python
|
|
153
|
+
from instructvault import InstructVault
|
|
154
|
+
|
|
155
|
+
vault = InstructVault(repo_root=".")
|
|
156
|
+
msgs = vault.render("prompts/support_reply.prompt.yml", vars={"ticket_text":"Order delayed"})
|
|
157
|
+
|
|
158
|
+
# Custom checks here
|
|
159
|
+
assert any("Ticket:" in m.content for m in msgs)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Or plug in a policy module:
|
|
163
|
+
```bash
|
|
164
|
+
ivault eval prompts/support_reply.prompt.yml --policy my_policy.py
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Policy module signature:
|
|
168
|
+
```python
|
|
169
|
+
def check_spec(spec: dict) -> list[str]:
|
|
170
|
+
return []
|
|
171
|
+
|
|
172
|
+
def check_render(text: str, context: dict) -> list[str]:
|
|
173
|
+
return []
|
|
174
|
+
```
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Spec Contract
|
|
2
|
+
|
|
3
|
+
## Versioning
|
|
4
|
+
- `spec_version` is required for prompts.
|
|
5
|
+
- Current stable series: **1.x**
|
|
6
|
+
- Minor versions (1.1, 1.2, …) must remain backward compatible with 1.0.
|
|
7
|
+
- Breaking changes require a major version (2.0).
|
|
8
|
+
|
|
9
|
+
## Deprecation
|
|
10
|
+
- Deprecated fields must continue to parse for at least one minor release.
|
|
11
|
+
- Deprecations are documented in `CHANGELOG.md`.
|
|
12
|
+
|
|
13
|
+
## Migration
|
|
14
|
+
Use:
|
|
15
|
+
```
|
|
16
|
+
ivault migrate prompts
|
|
17
|
+
```
|
|
18
|
+
This checks for missing `spec_version` and reports any files that need updates.
|
|
19
|
+
Use `--apply` to write `spec_version: 1.0` into YAML prompts.
|
|
20
|
+
|
|
21
|
+
## Data Model (1.0)
|
|
22
|
+
Required:
|
|
23
|
+
- `spec_version`
|
|
24
|
+
- `name`
|
|
25
|
+
- `messages`
|
|
26
|
+
- `tests` (at least one inline test)
|
|
27
|
+
|
|
28
|
+
Optional:
|
|
29
|
+
- `description`
|
|
30
|
+
- `modelParameters` (alias: `model_defaults`)
|
|
31
|
+
- `variables`
|
|
32
|
+
|
|
33
|
+
## Tests
|
|
34
|
+
Each test must include at least one assertion:
|
|
35
|
+
- `contains_any`
|
|
36
|
+
- `contains_all`
|
|
37
|
+
- `not_contains`
|
|
38
|
+
- `matches` (regex)
|
|
39
|
+
- `not_matches` (regex)
|
|
40
|
+
- `json_schema` (JSON Schema validation)
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"id": "e4b28969",
|
|
6
|
+
"metadata": {},
|
|
7
|
+
"source": [
|
|
8
|
+
"# InstructVault Quickstart (Google Colab)\n",
|
|
9
|
+
"\n",
|
|
10
|
+
"This notebook is designed for Colab. It uses `/content/ivault_demo` and repo-relative prompt paths."
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"cell_type": "code",
|
|
15
|
+
"execution_count": null,
|
|
16
|
+
"id": "79ef050d",
|
|
17
|
+
"metadata": {},
|
|
18
|
+
"outputs": [],
|
|
19
|
+
"source": [
|
|
20
|
+
"!pip -q install instructvault\n"
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"cell_type": "code",
|
|
25
|
+
"execution_count": null,
|
|
26
|
+
"id": "d416a2e3",
|
|
27
|
+
"metadata": {},
|
|
28
|
+
"outputs": [],
|
|
29
|
+
"source": [
|
|
30
|
+
"# If you're not on Colab, change this path to your local repo folder.\n",
|
|
31
|
+
"repo_path = \"/content/ivault_demo\"\n",
|
|
32
|
+
"print(\"Using repo_path:\", repo_path)"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"cell_type": "code",
|
|
37
|
+
"execution_count": null,
|
|
38
|
+
"id": "5c257338",
|
|
39
|
+
"metadata": {},
|
|
40
|
+
"outputs": [],
|
|
41
|
+
"source": [
|
|
42
|
+
"from pathlib import Path\n",
|
|
43
|
+
"\n",
|
|
44
|
+
"repo = Path(\"/content/content/ivault_demo\")\n",
|
|
45
|
+
"(repo / \"prompts\").mkdir(parents=True, exist_ok=True)\n",
|
|
46
|
+
"\n",
|
|
47
|
+
"prompt_text = '''spec_version: \"1.0\"\n",
|
|
48
|
+
"name: hello_world\n",
|
|
49
|
+
"variables:\n",
|
|
50
|
+
" required: [name]\n",
|
|
51
|
+
"messages:\n",
|
|
52
|
+
" - role: system\n",
|
|
53
|
+
" content: \"You are a helpful assistant.\"\n",
|
|
54
|
+
" - role: user\n",
|
|
55
|
+
" content: \"Say hello to {{ name }}.\"\n",
|
|
56
|
+
"tests:\n",
|
|
57
|
+
" - name: includes_name\n",
|
|
58
|
+
" vars: { name: \"Ava\" }\n",
|
|
59
|
+
" assert: { contains_any: [\"Ava\"] }\n",
|
|
60
|
+
"'''\n",
|
|
61
|
+
"\n",
|
|
62
|
+
"(repo / \"prompts\" / \"hello_world.prompt.yml\").write_text(prompt_text, encoding=\"utf-8\")\n",
|
|
63
|
+
"print(\"Prompt written:\", repo / \"prompts\" / \"hello_world.prompt.yml\")\n"
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"cell_type": "code",
|
|
68
|
+
"execution_count": null,
|
|
69
|
+
"id": "33a7f7bd",
|
|
70
|
+
"metadata": {},
|
|
71
|
+
"outputs": [],
|
|
72
|
+
"source": [
|
|
73
|
+
"!ivault validate /content/content/ivault_demo/prompts\n"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"cell_type": "code",
|
|
78
|
+
"execution_count": null,
|
|
79
|
+
"id": "040f198b",
|
|
80
|
+
"metadata": {},
|
|
81
|
+
"outputs": [],
|
|
82
|
+
"source": [
|
|
83
|
+
"from instructvault import InstructVault\n",
|
|
84
|
+
"\n",
|
|
85
|
+
"vault = InstructVault(repo_root=\"/content/ivault_demo\")\n",
|
|
86
|
+
"msgs = vault.render(\"prompts/hello_world.prompt.yml\", vars={\"name\":\"Colab\"})\n",
|
|
87
|
+
"print(msgs)\n"
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"cell_type": "code",
|
|
92
|
+
"execution_count": null,
|
|
93
|
+
"id": "1d6f8472",
|
|
94
|
+
"metadata": {},
|
|
95
|
+
"outputs": [],
|
|
96
|
+
"source": [
|
|
97
|
+
"!ivault eval /ivault_demo/prompts/hello_world.prompt.yml --report /ivault_demo/out/report.json\n"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"cell_type": "code",
|
|
102
|
+
"execution_count": null,
|
|
103
|
+
"id": "a5ba9974",
|
|
104
|
+
"metadata": {},
|
|
105
|
+
"outputs": [],
|
|
106
|
+
"source": [
|
|
107
|
+
"!ivault bundle --repo /content/ivault_demo --prompts prompts --out /content/ivault_demo/out/ivault.bundle.json"
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
"metadata": {
|
|
112
|
+
"colab": {
|
|
113
|
+
"name": "instructvault_colab.ipynb",
|
|
114
|
+
"provenance": []
|
|
115
|
+
},
|
|
116
|
+
"kernelspec": {
|
|
117
|
+
"display_name": "Python 3",
|
|
118
|
+
"language": "python",
|
|
119
|
+
"name": "python3"
|
|
120
|
+
},
|
|
121
|
+
"language_info": {
|
|
122
|
+
"name": "python",
|
|
123
|
+
"version": "3.x"
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
"nbformat": 4,
|
|
127
|
+
"nbformat_minor": 5
|
|
128
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"metadata": {},
|
|
6
|
+
"source": [
|
|
7
|
+
"# InstructVault + OpenAI (Google Colab)\n\n",
|
|
8
|
+
"This notebook renders a prompt with InstructVault and sends it to the OpenAI API.\n\n",
|
|
9
|
+
"**Note:** Keep your API key private. Do not commit it to source control."
|
|
10
|
+
]
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"cell_type": "code",
|
|
14
|
+
"execution_count": null,
|
|
15
|
+
"metadata": {},
|
|
16
|
+
"outputs": [],
|
|
17
|
+
"source": [
|
|
18
|
+
"!pip -q install instructvault openai"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"cell_type": "code",
|
|
23
|
+
"execution_count": null,
|
|
24
|
+
"metadata": {},
|
|
25
|
+
"outputs": [],
|
|
26
|
+
"source": [
|
|
27
|
+
"import os, getpass\n",
|
|
28
|
+
"\n",
|
|
29
|
+
"if 'OPENAI_API_KEY' not in os.environ:\n",
|
|
30
|
+
" os.environ['OPENAI_API_KEY'] = getpass.getpass('Enter OpenAI API key: ')\n",
|
|
31
|
+
"print('API key set:', 'OPENAI_API_KEY' in os.environ)"
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"cell_type": "code",
|
|
36
|
+
"execution_count": null,
|
|
37
|
+
"metadata": {},
|
|
38
|
+
"outputs": [],
|
|
39
|
+
"source": [
|
|
40
|
+
"from pathlib import Path\n",
|
|
41
|
+
"\n",
|
|
42
|
+
"repo_path = '/content/ivault_demo'\n",
|
|
43
|
+
"repo = Path(repo_path)\n",
|
|
44
|
+
"(repo / 'prompts').mkdir(parents=True, exist_ok=True)\n",
|
|
45
|
+
"\n",
|
|
46
|
+
"prompt_text = '''spec_version: \"1.0\"\n",
|
|
47
|
+
"name: hello_world\n",
|
|
48
|
+
"variables:\n",
|
|
49
|
+
" required: [name]\n",
|
|
50
|
+
"messages:\n",
|
|
51
|
+
" - role: system\n",
|
|
52
|
+
" content: \"You are a helpful assistant.\"\n",
|
|
53
|
+
" - role: user\n",
|
|
54
|
+
" content: \"Say hello to {{ name }}.\"\n",
|
|
55
|
+
"tests:\n",
|
|
56
|
+
" - name: includes_name\n",
|
|
57
|
+
" vars: { name: \"Ava\" }\n",
|
|
58
|
+
" assert: { contains_any: [\"Ava\"] }\n",
|
|
59
|
+
"'''\n",
|
|
60
|
+
"\n",
|
|
61
|
+
"(repo / 'prompts' / 'hello_world.prompt.yml').write_text(prompt_text, encoding='utf-8')\n",
|
|
62
|
+
"print('Prompt written:', repo / 'prompts' / 'hello_world.prompt.yml')"
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"cell_type": "code",
|
|
67
|
+
"execution_count": null,
|
|
68
|
+
"metadata": {},
|
|
69
|
+
"outputs": [],
|
|
70
|
+
"source": [
|
|
71
|
+
"from instructvault import InstructVault\n",
|
|
72
|
+
"\n",
|
|
73
|
+
"vault = InstructVault(repo_root=repo_path)\n",
|
|
74
|
+
"messages = vault.render('prompts/hello_world.prompt.yml', vars={'name':'Colab'})\n",
|
|
75
|
+
"messages"
|
|
76
|
+
]
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"cell_type": "code",
|
|
80
|
+
"execution_count": null,
|
|
81
|
+
"metadata": {},
|
|
82
|
+
"outputs": [],
|
|
83
|
+
"source": [
|
|
84
|
+
"from openai import OpenAI\n",
|
|
85
|
+
"\n",
|
|
86
|
+
"client = OpenAI()\n",
|
|
87
|
+
"response = client.chat.completions.create(\n",
|
|
88
|
+
" model='gpt-4.1',\n",
|
|
89
|
+
" messages=messages,\n",
|
|
90
|
+
")\n",
|
|
91
|
+
"print(response.choices[0].message.content)"
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"metadata": {
|
|
96
|
+
"colab": {
|
|
97
|
+
"name": "instructvault_openai_colab.ipynb",
|
|
98
|
+
"provenance": []
|
|
99
|
+
},
|
|
100
|
+
"kernelspec": {
|
|
101
|
+
"display_name": "Python 3",
|
|
102
|
+
"language": "python",
|
|
103
|
+
"name": "python3"
|
|
104
|
+
},
|
|
105
|
+
"language_info": {
|
|
106
|
+
"name": "python",
|
|
107
|
+
"version": "3.x"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"nbformat": 4,
|
|
111
|
+
"nbformat_minor": 5
|
|
112
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cells": [
|
|
3
|
+
{
|
|
4
|
+
"cell_type": "markdown",
|
|
5
|
+
"metadata": {},
|
|
6
|
+
"source": [
|
|
7
|
+
"# InstructVault RAG Cookbook (Google Colab)\n\n",
|
|
8
|
+
"This notebook shows a simple RAG prompt and an agentic RAG prompt using InstructVault."
|
|
9
|
+
]
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"cell_type": "code",
|
|
13
|
+
"execution_count": null,
|
|
14
|
+
"metadata": {},
|
|
15
|
+
"outputs": [],
|
|
16
|
+
"source": [
|
|
17
|
+
"!pip -q install instructvault"
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"cell_type": "code",
|
|
22
|
+
"execution_count": null,
|
|
23
|
+
"metadata": {},
|
|
24
|
+
"outputs": [],
|
|
25
|
+
"source": [
|
|
26
|
+
"# If you're not on Colab, change this path to your local repo folder.\n",
|
|
27
|
+
"repo_path = \"/content/ivault_demo\"\n",
|
|
28
|
+
"print(\"Using repo_path:\", repo_path)"
|
|
29
|
+
]
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"cell_type": "code",
|
|
33
|
+
"execution_count": null,
|
|
34
|
+
"metadata": {},
|
|
35
|
+
"outputs": [],
|
|
36
|
+
"source": [
|
|
37
|
+
"from pathlib import Path\n",
|
|
38
|
+
"\n",
|
|
39
|
+
"repo = Path(repo_path)\n",
|
|
40
|
+
"(repo / \"prompts\").mkdir(parents=True, exist_ok=True)\n",
|
|
41
|
+
"\n",
|
|
42
|
+
"rag_prompt = '''spec_version: \"1.0\"\n",
|
|
43
|
+
"name: rag_answer\n",
|
|
44
|
+
"variables:\n",
|
|
45
|
+
" required: [question, context]\n",
|
|
46
|
+
"messages:\n",
|
|
47
|
+
" - role: system\n",
|
|
48
|
+
" content: \"Answer using only the provided context. If missing, say you don't know.\"\n",
|
|
49
|
+
" - role: user\n",
|
|
50
|
+
" content: \"Question: {{ question }}\\n\\nContext:\\n{{ context }}\"\n",
|
|
51
|
+
"tests:\n",
|
|
52
|
+
" - name: includes_context\n",
|
|
53
|
+
" vars: { question: \"What is InstructVault?\", context: \"InstructVault is a Git-first prompt registry.\" }\n",
|
|
54
|
+
" assert: { contains_any: [\"Context:\"] }\n",
|
|
55
|
+
"'''\n",
|
|
56
|
+
"\n",
|
|
57
|
+
"agent_prompt = '''spec_version: \"1.0\"\n",
|
|
58
|
+
"name: rag_agent\n",
|
|
59
|
+
"variables:\n",
|
|
60
|
+
" required: [question]\n",
|
|
61
|
+
"messages:\n",
|
|
62
|
+
" - role: system\n",
|
|
63
|
+
" content: \"You are a retrieval-augmented agent. Use tools when needed and cite evidence.\"\n",
|
|
64
|
+
" - role: user\n",
|
|
65
|
+
" content: \"Question: {{ question }}\"\n",
|
|
66
|
+
"tests:\n",
|
|
67
|
+
" - name: includes_question\n",
|
|
68
|
+
" vars: { question: \"What is prompt versioning?\" }\n",
|
|
69
|
+
" assert: { contains_any: [\"Question:\"] }\n",
|
|
70
|
+
"'''\n",
|
|
71
|
+
"\n",
|
|
72
|
+
"(repo / \"prompts\" / \"rag_answer.prompt.yml\").write_text(rag_prompt, encoding=\"utf-8\")\n",
|
|
73
|
+
"(repo / \"prompts\" / \"rag_agent.prompt.yml\").write_text(agent_prompt, encoding=\"utf-8\")\n",
|
|
74
|
+
"print(\"Wrote prompts in\", repo / \"prompts\")"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"cell_type": "code",
|
|
79
|
+
"execution_count": null,
|
|
80
|
+
"metadata": {},
|
|
81
|
+
"outputs": [],
|
|
82
|
+
"source": [
|
|
83
|
+
"!ivault validate /content/ivault_demo/prompts"
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"cell_type": "code",
|
|
88
|
+
"execution_count": null,
|
|
89
|
+
"metadata": {},
|
|
90
|
+
"outputs": [],
|
|
91
|
+
"source": [
|
|
92
|
+
"from instructvault import InstructVault\n",
|
|
93
|
+
"\n",
|
|
94
|
+
"vault = InstructVault(repo_root=repo_path)\n",
|
|
95
|
+
"context = \"InstructVault keeps prompts in Git and uses CI for evals.\"\n",
|
|
96
|
+
"msgs = vault.render(\"prompts/rag_answer.prompt.yml\", vars={\"question\": \"What is InstructVault?\", \"context\": context})\n",
|
|
97
|
+
"print(msgs)"
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"cell_type": "code",
|
|
102
|
+
"execution_count": null,
|
|
103
|
+
"metadata": {},
|
|
104
|
+
"outputs": [],
|
|
105
|
+
"source": [
|
|
106
|
+
"!ivault eval /content/ivault_demo/prompts/rag_answer.prompt.yml --report /content/ivault_demo/out/rag_report.json"
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
],
|
|
110
|
+
"metadata": {
|
|
111
|
+
"colab": {
|
|
112
|
+
"name": "instructvault_rag_colab.ipynb",
|
|
113
|
+
"provenance": []
|
|
114
|
+
},
|
|
115
|
+
"kernelspec": {
|
|
116
|
+
"display_name": "Python 3",
|
|
117
|
+
"language": "python",
|
|
118
|
+
"name": "python3"
|
|
119
|
+
},
|
|
120
|
+
"language_info": {
|
|
121
|
+
"name": "python",
|
|
122
|
+
"version": "3.x"
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"nbformat": 4,
|
|
126
|
+
"nbformat_minor": 5
|
|
127
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
def check_spec(spec: dict) -> list[str]:
|
|
2
|
+
errors = []
|
|
3
|
+
name = spec.get("name", "")
|
|
4
|
+
if name.startswith("unsafe_"):
|
|
5
|
+
errors.append("prompt name cannot start with 'unsafe_'")
|
|
6
|
+
return errors
|
|
7
|
+
|
|
8
|
+
def check_render(text: str, context: dict) -> list[str]:
|
|
9
|
+
errors = []
|
|
10
|
+
forbidden = ["SSN", "credit card", "password"]
|
|
11
|
+
lowered = text.lower()
|
|
12
|
+
if any(f.lower() in lowered for f in forbidden):
|
|
13
|
+
errors.append("rendered output contains forbidden phrase")
|
|
14
|
+
return errors
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
EMAIL = re.compile(r"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}")
|
|
4
|
+
SSN = re.compile(r"\\b\\d{3}-\\d{2}-\\d{4}\\b")
|
|
5
|
+
CC = re.compile(r"\\b(?:\\d[ -]*?){13,16}\\b")
|
|
6
|
+
|
|
7
|
+
FORBIDDEN = ["password", "credit card", "ssn"]
|
|
8
|
+
|
|
9
|
+
def check_spec(spec: dict) -> list[str]:
|
|
10
|
+
errors = []
|
|
11
|
+
if spec.get("name", "").startswith("unsafe_"):
|
|
12
|
+
errors.append("prompt name cannot start with 'unsafe_'")
|
|
13
|
+
return errors
|
|
14
|
+
|
|
15
|
+
def check_render(text: str, context: dict) -> list[str]:
|
|
16
|
+
errors = []
|
|
17
|
+
if EMAIL.search(text):
|
|
18
|
+
errors.append("PII detected: email")
|
|
19
|
+
if SSN.search(text):
|
|
20
|
+
errors.append("PII detected: ssn")
|
|
21
|
+
if CC.search(text):
|
|
22
|
+
errors.append("PII detected: credit card")
|
|
23
|
+
lowered = text.lower()
|
|
24
|
+
if any(f in lowered for f in FORBIDDEN):
|
|
25
|
+
errors.append("forbidden phrase detected")
|
|
26
|
+
return errors
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "instructvault"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.3.0"
|
|
4
4
|
description = "Git-first prompt registry + CI evals + lightweight runtime SDK (ivault)."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -12,6 +12,7 @@ dependencies = [
|
|
|
12
12
|
"pyyaml>=6.0",
|
|
13
13
|
"jinja2>=3.1",
|
|
14
14
|
"rich>=13.7",
|
|
15
|
+
"jsonschema>=4.21",
|
|
15
16
|
]
|
|
16
17
|
|
|
17
18
|
[project.optional-dependencies]
|