prysm1 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,52 @@
1
+ # Environment
2
+ .env
3
+ *.env.local
4
+
5
+ # Python
6
+ __pycache__/
7
+ *.py[cod]
8
+ *.egg-info/
9
+ dist/
10
+ build/
11
+ .venv/
12
+ venv/
13
+
14
+ # Node
15
+ node_modules/
16
+ .next/
17
+ out/
18
+
19
+ # IDE
20
+ .vscode/
21
+ .idea/
22
+ *.swp
23
+ *.swo
24
+ .DS_Store
25
+
26
+ # Docker
27
+ *.log
28
+
29
+ # Outputs
30
+ *.tar.gz
31
+
32
+ # Database (SQLite — local/runtime state, never commit)
33
+ *.db
34
+ *.db-wal
35
+ *.db-shm
36
+ *.sqlite
37
+ *.sqlite3
38
+
39
+ # Benchmark data (fetched on demand; third-party licenses, e.g. AIME CC BY-NC-SA 4.0).
40
+ # We ship NO benchmark data in the repo — fetch_aime.py downloads it here at run time.
41
+ backend/eval/data/
42
+ eval/data/
43
+
44
+ # ── Docs internos sensibles (IP pre-patente) ──
45
+ # Excluidos por precaución (claims de patente sin presentar). Borra estas 2 líneas
46
+ # si quieres versionarlos en tu repo PRIVADO.
47
+ PRYSM-1-MODELO-DE-NEGOCIO.md
48
+ PRYSM-IP-OPORTUNIDADES.md
49
+
50
+ # Fixture huérfano de eval (ningún código lo referencia). Se mantiene local pero
51
+ # se destrackea para adelgazar el repo; recuperable del historial si se necesita.
52
+ backend/eval/_PILOT_test.pdf
prysm1-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,114 @@
1
+ Metadata-Version: 2.4
2
+ Name: prysm1
3
+ Version: 0.1.0
4
+ Summary: PRYSM — universal AI routing, OpenAI drop-in. One API, every model, always the best one.
5
+ Project-URL: Homepage, https://prysm1.com
6
+ Project-URL: Documentation, https://docs.prysm1.com
7
+ Author: PRYSM
8
+ License: Proprietary
9
+ Keywords: agents,ai,gateway,llm,openai,prysm,routing
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
13
+ Requires-Python: >=3.9
14
+ Requires-Dist: httpx>=0.27
15
+ Requires-Dist: openai>=1.40
16
+ Provides-Extra: yaml
17
+ Requires-Dist: pyyaml>=6.0; extra == 'yaml'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # prysm1 — PRYSM Python SDK
21
+
22
+ **One API, every model, always the best one.** An OpenAI drop-in: change one line,
23
+ get intelligent routing across 21 models, cost guardrails (AgentGuard), declarative
24
+ config (BRAIN.md), and cryptographic receipts (PrysmProof).
25
+
26
+ ```bash
27
+ pip install prysm1
28
+ ```
29
+
30
+ ## Drop-in replacement for OpenAI
31
+
32
+ `Prysm` subclasses `openai.OpenAI`, so all your existing code works unchanged.
33
+
34
+ ```python
35
+ from prysm import Prysm
36
+
37
+ client = Prysm() # api_key from $PRYSM_API_KEY, base_url from $PRYSM_BASE_URL
38
+
39
+ resp = client.chat.completions.create(
40
+ model="auto", # let PRYSM pick the best model
41
+ messages=[{"role": "user", "content": "Write a Python quicksort"}],
42
+ )
43
+ print(resp.choices[0].message.content)
44
+ ```
45
+
46
+ ### Access the PRYSM extensions
47
+
48
+ Every response carries a `prysm` block (routing, cost, latency, proof). Use
49
+ `extension()` for clean dot-access:
50
+
51
+ ```python
52
+ import prysm
53
+
54
+ ext = prysm.extension(resp)
55
+ print(ext.routing.model_display) # "DeepSeek V3.2"
56
+ print(ext.cost.total_usd) # 0.000042
57
+ print(ext.proof.proof_hash) # "sha256:a1b2c3d4..."
58
+ ```
59
+
60
+ ## BRAIN.md auto-discovery
61
+
62
+ Drop a `BRAIN.md` in your project root and the SDK finds it automatically, applying
63
+ your routing rules / cost caps / blocked models on every `complete()` call:
64
+
65
+ ```python
66
+ client = Prysm() # discovers ./BRAIN.md (walks up from cwd)
67
+ resp = client.complete("Summarize this contract") # BRAIN.md applied
68
+ ```
69
+
70
+ Point it explicitly, pass a dict, or disable:
71
+
72
+ ```python
73
+ Prysm(brain="path/to/BRAIN.md")
74
+ Prysm(brain={"max_cost": 0.005, "model": "deepseek-v3.2"})
75
+ Prysm(brain=None) # ignore BRAIN.md
76
+ ```
77
+
78
+ Validate a BRAIN.md before shipping:
79
+
80
+ ```python
81
+ print(client.validate_brain(open("BRAIN.md").read()))
82
+ # {'valid': True, 'errors': [], 'warnings': [], 'normalized': {...}}
83
+ ```
84
+
85
+ ## Helpers
86
+
87
+ ```python
88
+ client.route("debug this function") # dry-run: which model, est. cost (no call)
89
+ client.usage() # your usage stats
90
+ client.savings(baseline="gpt-5.2") # est. $ saved vs. an all-premium baseline
91
+ client.verify_proof(request_id) # verify a PrysmProof
92
+ client.models_catalog() # 21 models with pricing
93
+ ```
94
+
95
+ ## Configuration
96
+
97
+ | Setting | Argument | Env var | Default |
98
+ |---------|----------|---------|---------|
99
+ | API key | `api_key=` | `PRYSM_API_KEY` | — |
100
+ | Base URL | `base_url=` | `PRYSM_BASE_URL` | `https://api.prysm1.com/v1` |
101
+ | BRAIN.md | `brain=` | — | `"auto"` (discover) |
102
+
103
+ Get an API key at [prysm1.com](https://prysm1.com). Full docs at
104
+ [docs.prysm1.com](https://docs.prysm1.com).
105
+
106
+ ## Development
107
+
108
+ ```bash
109
+ python tests/test_sdk.py # no pytest required; runs against the backend in-process
110
+ ```
111
+
112
+ ## License
113
+
114
+ Proprietary.
prysm1-0.1.0/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # prysm1 — PRYSM Python SDK
2
+
3
+ **One API, every model, always the best one.** An OpenAI drop-in: change one line,
4
+ get intelligent routing across 21 models, cost guardrails (AgentGuard), declarative
5
+ config (BRAIN.md), and cryptographic receipts (PrysmProof).
6
+
7
+ ```bash
8
+ pip install prysm1
9
+ ```
10
+
11
+ ## Drop-in replacement for OpenAI
12
+
13
+ `Prysm` subclasses `openai.OpenAI`, so all your existing code works unchanged.
14
+
15
+ ```python
16
+ from prysm import Prysm
17
+
18
+ client = Prysm() # api_key from $PRYSM_API_KEY, base_url from $PRYSM_BASE_URL
19
+
20
+ resp = client.chat.completions.create(
21
+ model="auto", # let PRYSM pick the best model
22
+ messages=[{"role": "user", "content": "Write a Python quicksort"}],
23
+ )
24
+ print(resp.choices[0].message.content)
25
+ ```
26
+
27
+ ### Access the PRYSM extensions
28
+
29
+ Every response carries a `prysm` block (routing, cost, latency, proof). Use
30
+ `extension()` for clean dot-access:
31
+
32
+ ```python
33
+ import prysm
34
+
35
+ ext = prysm.extension(resp)
36
+ print(ext.routing.model_display) # "DeepSeek V3.2"
37
+ print(ext.cost.total_usd) # 0.000042
38
+ print(ext.proof.proof_hash) # "sha256:a1b2c3d4..."
39
+ ```
40
+
41
+ ## BRAIN.md auto-discovery
42
+
43
+ Drop a `BRAIN.md` in your project root and the SDK finds it automatically, applying
44
+ your routing rules / cost caps / blocked models on every `complete()` call:
45
+
46
+ ```python
47
+ client = Prysm() # discovers ./BRAIN.md (walks up from cwd)
48
+ resp = client.complete("Summarize this contract") # BRAIN.md applied
49
+ ```
50
+
51
+ Point it explicitly, pass a dict, or disable:
52
+
53
+ ```python
54
+ Prysm(brain="path/to/BRAIN.md")
55
+ Prysm(brain={"max_cost": 0.005, "model": "deepseek-v3.2"})
56
+ Prysm(brain=None) # ignore BRAIN.md
57
+ ```
58
+
59
+ Validate a BRAIN.md before shipping:
60
+
61
+ ```python
62
+ print(client.validate_brain(open("BRAIN.md").read()))
63
+ # {'valid': True, 'errors': [], 'warnings': [], 'normalized': {...}}
64
+ ```
65
+
66
+ ## Helpers
67
+
68
+ ```python
69
+ client.route("debug this function") # dry-run: which model, est. cost (no call)
70
+ client.usage() # your usage stats
71
+ client.savings(baseline="gpt-5.2") # est. $ saved vs. an all-premium baseline
72
+ client.verify_proof(request_id) # verify a PrysmProof
73
+ client.models_catalog() # 21 models with pricing
74
+ ```
75
+
76
+ ## Configuration
77
+
78
+ | Setting | Argument | Env var | Default |
79
+ |---------|----------|---------|---------|
80
+ | API key | `api_key=` | `PRYSM_API_KEY` | — |
81
+ | Base URL | `base_url=` | `PRYSM_BASE_URL` | `https://api.prysm1.com/v1` |
82
+ | BRAIN.md | `brain=` | — | `"auto"` (discover) |
83
+
84
+ Get an API key at [prysm1.com](https://prysm1.com). Full docs at
85
+ [docs.prysm1.com](https://docs.prysm1.com).
86
+
87
+ ## Development
88
+
89
+ ```bash
90
+ python tests/test_sdk.py # no pytest required; runs against the backend in-process
91
+ ```
92
+
93
+ ## License
94
+
95
+ Proprietary.
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "prysm1"
7
+ version = "0.1.0"
8
+ description = "PRYSM — universal AI routing, OpenAI drop-in. One API, every model, always the best one."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = { text = "Proprietary" }
12
+ authors = [{ name = "PRYSM" }]
13
+ keywords = ["ai", "llm", "routing", "openai", "gateway", "prysm", "agents"]
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "Intended Audience :: Developers",
17
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
18
+ ]
19
+ dependencies = [
20
+ "openai>=1.40",
21
+ "httpx>=0.27",
22
+ ]
23
+
24
+ [project.optional-dependencies]
25
+ yaml = ["pyyaml>=6.0"]
26
+
27
+ [project.scripts]
28
+ prysm = "prysm.cli:main"
29
+
30
+ [project.urls]
31
+ Homepage = "https://prysm1.com"
32
+ Documentation = "https://docs.prysm1.com"
33
+
34
+ [tool.hatch.build.targets.wheel]
35
+ packages = ["src/prysm"]
@@ -0,0 +1,31 @@
1
+ """
2
+ prysm1 — PRYSM Python SDK.
3
+
4
+ One API, every model, always the best one. An OpenAI drop-in:
5
+
6
+ from prysm import Prysm
7
+ client = Prysm()
8
+ resp = client.chat.completions.create(
9
+ model="auto",
10
+ messages=[{"role": "user", "content": "Hello"}],
11
+ )
12
+ print(prysm.extension(resp).routing.model_display)
13
+ """
14
+ from .brain import find_brain, load_brain, normalize_brain, parse_brain
15
+ from .client import Prysm
16
+ from .extensions import cost, extension, proof, routing
17
+
18
+ __version__ = "0.1.0"
19
+
20
+ __all__ = [
21
+ "Prysm",
22
+ "extension",
23
+ "routing",
24
+ "cost",
25
+ "proof",
26
+ "load_brain",
27
+ "find_brain",
28
+ "parse_brain",
29
+ "normalize_brain",
30
+ "__version__",
31
+ ]
@@ -0,0 +1,208 @@
1
+ """
2
+ prysm.brain — client-side BRAIN.md discovery + parsing.
3
+
4
+ Mirrors the server's parser so the SDK can auto-discover a project's BRAIN.md and
5
+ inject it into requests without a network round-trip. Uses PyYAML when present,
6
+ falls back to a dependency-free subset parser.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ from typing import Any, Optional
12
+
13
+ # BRAIN.md 'when' vocabulary -> canonical router signals.
14
+ SIGNAL_ALIASES = {
15
+ "code": "code", "coding": "code", "programming": "code", "dev": "code",
16
+ "write": "write", "writing": "write", "content": "write", "copy": "write", "copywriting": "write",
17
+ "analysis": "analysis", "research": "analysis", "analyze": "analysis", "analyse": "analysis",
18
+ "math": "math", "maths": "math", "calculation": "math", "calc": "math",
19
+ "translate": "translate", "translation": "translate", "i18n": "translate",
20
+ "realtime": "realtime", "real-time": "realtime", "news": "realtime", "live": "realtime",
21
+ "simple": "simple", "quick": "simple", "lookup": "simple",
22
+ "multimodal": "multimodal", "vision": "multimodal", "image": "multimodal", "images": "multimodal",
23
+ "reasoning": "reasoning", "logic": "reasoning", "reason": "reasoning",
24
+ }
25
+
26
+
27
+ def _split_commas(s: str) -> list:
28
+ out, buf, q = [], "", None
29
+ for ch in s:
30
+ if q:
31
+ buf += ch
32
+ if ch == q:
33
+ q = None
34
+ elif ch in ("'", '"'):
35
+ q = ch
36
+ buf += ch
37
+ elif ch == ",":
38
+ out.append(buf)
39
+ buf = ""
40
+ else:
41
+ buf += ch
42
+ if buf.strip():
43
+ out.append(buf)
44
+ return out
45
+
46
+
47
+ def _coerce(v: str) -> Any:
48
+ s = v.strip()
49
+ if not s:
50
+ return ""
51
+ if s.startswith("[") and s.endswith("]"):
52
+ inner = s[1:-1].strip()
53
+ return [] if not inner else [_coerce(x) for x in _split_commas(inner)]
54
+ if len(s) >= 2 and s[0] == s[-1] and s[0] in ("'", '"'):
55
+ return s[1:-1]
56
+ low = s.lower()
57
+ if low in ("true", "yes", "on"):
58
+ return True
59
+ if low in ("false", "no", "off"):
60
+ return False
61
+ if low in ("null", "none", "~"):
62
+ return None
63
+ try:
64
+ return float(s) if ("." in s or "e" in low) else int(s)
65
+ except ValueError:
66
+ return s
67
+
68
+
69
+ def _strip_inline_comment(line: str) -> str:
70
+ q = None
71
+ for i, ch in enumerate(line):
72
+ if q:
73
+ if ch == q:
74
+ q = None
75
+ elif ch in ("'", '"'):
76
+ q = ch
77
+ elif ch == "#" and (i == 0 or line[i - 1] in (" ", "\t")):
78
+ return line[:i]
79
+ return line
80
+
81
+
82
+ def _parse_subset(text: str) -> dict:
83
+ data: dict = {}
84
+ cur_key = None
85
+ cur_list = None
86
+ cur_dict = None
87
+ for raw in text.splitlines():
88
+ line = _strip_inline_comment(raw)
89
+ if not line.strip():
90
+ continue
91
+ stripped = line.strip()
92
+ indent = len(line) - len(line.lstrip())
93
+ if stripped.startswith("- "):
94
+ item = stripped[2:].strip()
95
+ if cur_list is None:
96
+ cur_list = []
97
+ if cur_key is not None:
98
+ data[cur_key] = cur_list
99
+ if ":" in item and item[0] not in ("'", '"'):
100
+ k, _, v = item.partition(":")
101
+ cur_dict = {k.strip(): _coerce(v)}
102
+ cur_list.append(cur_dict)
103
+ else:
104
+ cur_dict = None
105
+ cur_list.append(_coerce(item))
106
+ continue
107
+ if indent > 0 and cur_dict is not None and ":" in stripped:
108
+ k, _, v = stripped.partition(":")
109
+ cur_dict[k.strip()] = _coerce(v)
110
+ continue
111
+ if ":" in stripped:
112
+ k, _, v = stripped.partition(":")
113
+ cur_key = k.strip()
114
+ cur_list = None
115
+ cur_dict = None
116
+ data[cur_key] = _coerce(v.strip()) if v.strip() != "" else None
117
+ return data
118
+
119
+
120
+ def parse_brain(text: str) -> dict:
121
+ """Parse BRAIN.md text into a raw mapping. Uses PyYAML when available."""
122
+ if not text or not text.strip():
123
+ return {}
124
+ try:
125
+ import yaml # type: ignore
126
+ data = yaml.safe_load(text)
127
+ if isinstance(data, dict):
128
+ return data
129
+ except Exception:
130
+ pass
131
+ return _parse_subset(text)
132
+
133
+
134
+ def normalize_brain(raw: dict) -> dict:
135
+ """Map a raw BRAIN.md mapping to the canonical config the router consumes."""
136
+ raw = raw or {}
137
+ n: dict = {}
138
+ if raw.get("name"):
139
+ n["name"] = raw["name"]
140
+ if raw.get("version") is not None:
141
+ n["version"] = raw["version"]
142
+ if raw.get("model"):
143
+ n["model"] = raw["model"]
144
+ cap = raw.get("max_cost", raw.get("max_cost_per_request"))
145
+ if cap is not None:
146
+ n["max_cost"] = cap
147
+ if raw.get("monthly_budget") is not None:
148
+ n["monthly_budget"] = raw["monthly_budget"]
149
+ rules = []
150
+ for r in (raw.get("rules") or []):
151
+ if isinstance(r, dict) and r.get("when") and r.get("model"):
152
+ w = str(r["when"]).strip().lower()
153
+ rules.append({
154
+ "when": SIGNAL_ALIASES.get(w, w),
155
+ "model": r["model"],
156
+ "reason": r.get("reason", ""),
157
+ })
158
+ if rules:
159
+ n["rules"] = rules
160
+ if raw.get("blocked"):
161
+ n["blocked"] = [str(x) for x in raw["blocked"]]
162
+ if raw.get("fallback"):
163
+ n["fallback"] = [str(x) for x in raw["fallback"]]
164
+ if raw.get("quality_threshold") is not None:
165
+ n["quality_threshold"] = raw["quality_threshold"]
166
+ if raw.get("quality_signals"):
167
+ n["quality_signals"] = raw["quality_signals"]
168
+ if raw.get("log_level"):
169
+ n["log_level"] = raw["log_level"]
170
+ if raw.get("log_proofs") is not None:
171
+ n["log_proofs"] = raw["log_proofs"]
172
+ return n
173
+
174
+
175
+ def find_brain(start: Optional[str] = None) -> Optional[str]:
176
+ """Walk up from `start` (or cwd) looking for a BRAIN.md. Returns its path or None."""
177
+ d = os.path.abspath(start or os.getcwd())
178
+ if os.path.isfile(d): # a file was passed
179
+ return d if os.path.basename(d) == "BRAIN.md" else None
180
+ while True:
181
+ candidate = os.path.join(d, "BRAIN.md")
182
+ if os.path.isfile(candidate):
183
+ return candidate
184
+ parent = os.path.dirname(d)
185
+ if parent == d:
186
+ return None
187
+ d = parent
188
+
189
+
190
+ def load_brain(path_or_dir: Optional[str] = None) -> Optional[dict]:
191
+ """Discover (or read) a BRAIN.md and return its normalized config, or None.
192
+
193
+ - None -> auto-discover by walking up from cwd
194
+ - a directory -> auto-discover from there
195
+ - a file path -> read that file
196
+ """
197
+ path = path_or_dir
198
+ if path is None or os.path.isdir(path or ""):
199
+ path = find_brain(path)
200
+ if not path or not os.path.isfile(path):
201
+ return None
202
+ try:
203
+ with open(path, encoding="utf-8") as f:
204
+ text = f.read()
205
+ except OSError:
206
+ return None
207
+ normalized = normalize_brain(parse_brain(text))
208
+ return normalized or None