sqlite-jev 0.1.0__py3-none-macosx_11_0_arm64.whl

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.
sqlite_jev/__init__.py ADDED
@@ -0,0 +1,31 @@
1
+ """Load sqlite-jev into a Python SQLite connection."""
2
+
3
+ from importlib.metadata import version
4
+ from importlib.resources import as_file, files
5
+ import sys
6
+
7
+
8
+ __version__ = version("sqlite-jev")
9
+
10
+
11
+ def load(connection):
12
+ """Load sqlite-jev into a stdlib sqlite3 connection and return it."""
13
+ if not hasattr(connection, "enable_load_extension"):
14
+ raise RuntimeError(
15
+ "this Python sqlite3 build does not support loadable extensions"
16
+ )
17
+
18
+ suffix = ".dylib" if sys.platform == "darwin" else ".so"
19
+ extension = files(__package__).joinpath(f"jev{suffix}")
20
+
21
+ with as_file(extension) as path:
22
+ connection.enable_load_extension(True)
23
+ try:
24
+ connection.load_extension(str(path))
25
+ finally:
26
+ connection.enable_load_extension(False)
27
+
28
+ return connection
29
+
30
+
31
+ __all__ = ["__version__", "load"]
sqlite_jev/jev.dylib ADDED
Binary file
@@ -0,0 +1,259 @@
1
+ Metadata-Version: 2.2
2
+ Name: sqlite-jev
3
+ Version: 0.1.0
4
+ Summary: Batched natural-language judgments for SQLite, powered by TypeSafe Jev
5
+ Classifier: Programming Language :: Python :: 3
6
+ Classifier: Programming Language :: SQL
7
+ Classifier: Operating System :: MacOS
8
+ Classifier: Operating System :: POSIX :: Linux
9
+ Classifier: Topic :: Database
10
+ Project-URL: Source, https://github.com/mgaitan/sqlite-jev
11
+ Project-URL: Issues, https://github.com/mgaitan/sqlite-jev/issues
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+
15
+ # sqlite-jev
16
+
17
+ Natural-language predicates, classification, and scoring for SQLite, powered by
18
+ [TypeSafe Jev](https://docs.typesafe.ai). It is inspired by
19
+ [`pg-jev`](https://github.com/realZachi/pg-jev), but shaped around SQLite's loadable-extension
20
+ and virtual-table APIs.
21
+
22
+ ```sql
23
+ .load ./build/jev
24
+
25
+ SELECT t.id, t.subject, round(j.probability, 3) AS urgency
26
+ FROM jev_rows(
27
+ 'tickets',
28
+ 'The customer explicitly expresses urgency or says work is blocked',
29
+ 'noul',
30
+ NULL,
31
+ json_array('subject', 'message')
32
+ ) AS j
33
+ JOIN tickets AS t ON t.rowid = j.source_rowid
34
+ WHERE j.probability >= 0.6;
35
+ ```
36
+
37
+ `jev_rows` reads the selected columns, puts up to 40 rows in one shared state, asks one
38
+ question per row, and returns a virtual table that can be joined to the source by `rowid`.
39
+ Results are cached for the lifetime of the SQLite connection.
40
+
41
+ ## Build
42
+
43
+ Requirements:
44
+
45
+ - SQLite 3.45 or newer, built with JSON support and loadable extensions
46
+ - A C11 compiler and `make`
47
+ - The `libcurl` runtime (`libcurl.so.4` on Linux or `libcurl.4.dylib` on macOS)
48
+ - A TypeSafe API key
49
+
50
+ The current development machine already has all of these; no extra system package is needed.
51
+
52
+ ```bash
53
+ make
54
+ export TYPESAFE_API_KEY=...
55
+ sqlite3 my.db
56
+ ```
57
+
58
+ Inside SQLite:
59
+
60
+ ```sql
61
+ .load ./build/jev
62
+ SELECT jev_version();
63
+ ```
64
+
65
+ `TYPESAFE_API_KEY` is the only environment variable used for the API key.
66
+
67
+ ## Batched table queries
68
+
69
+ The signature is:
70
+
71
+ ```sql
72
+ jev_rows(table_name, question [, kind [, criteria [, columns]]])
73
+ ```
74
+
75
+ It returns `source_rowid`, `answer`, `probability`, `choice`, `score`, and `confidence`.
76
+ Columns that do not apply to the chosen primitive are `NULL`.
77
+
78
+ ### Boolean judgment (Noul)
79
+
80
+ ```sql
81
+ SELECT
82
+ t.id,
83
+ j.probability AS yes_probability,
84
+ 1.0 - j.probability AS no_probability,
85
+ CASE WHEN j.probability >= 0.7 THEN 'yes' ELSE 'no' END AS answer
86
+ FROM jev_rows(
87
+ 'tickets',
88
+ 'The ticket explicitly asks for a refund',
89
+ 'noul',
90
+ NULL,
91
+ json_array('subject', 'message')
92
+ ) AS j
93
+ JOIN tickets AS t ON t.rowid = j.source_rowid
94
+ ORDER BY t.id;
95
+ ```
96
+
97
+ A Noul returns the probability of `yes`; `no` is its complement. Choosing the larger one is
98
+ equivalent to a `0.5` threshold. Keep the threshold in SQL so it can rise with the cost of a
99
+ false positive. The scalar `jev(state, condition)` uses `0.5` unless given a third argument.
100
+
101
+ ### Classification (Choice)
102
+
103
+ ```sql
104
+ SELECT t.id, j.choice AS team, j.confidence
105
+ FROM jev_rows(
106
+ 'tickets',
107
+ 'Which team should handle the main request?',
108
+ 'choice',
109
+ json_object(
110
+ 'billing', 'Charges, invoices, payment methods, or refunds',
111
+ 'technical', 'Bugs, failures, or integrations',
112
+ 'sales', 'Pricing, plans, demos, or new purchases',
113
+ 'other', 'Anything outside those teams'
114
+ ),
115
+ json_array('subject', 'message')
116
+ ) AS j
117
+ JOIN tickets AS t ON t.rowid = j.source_rowid;
118
+ ```
119
+
120
+ ### Ordered rating (Score)
121
+
122
+ ```sql
123
+ SELECT t.id, j.score, j.confidence
124
+ FROM jev_rows(
125
+ 'tickets',
126
+ 'How frustrated is the customer?',
127
+ 'score',
128
+ json_array('Calm and factual', 'Frustrated but civil', 'Very angry or abusive'),
129
+ json_array('message')
130
+ ) AS j
131
+ JOIN tickets AS t ON t.rowid = j.source_rowid;
132
+ ```
133
+
134
+ For accuracy and cost, include only the columns the judgment needs. `jev_rows` requires a
135
+ rowid table. To prefilter a large data set, materialize the filtered rows into a temporary
136
+ table and evaluate that table.
137
+
138
+ ## Scalar functions
139
+
140
+ Scalar functions are convenient for one record. When scanning a table, prefer `jev_rows` so
141
+ Jev can evaluate many questions in a single request.
142
+
143
+ | Function | Result |
144
+ | --- | --- |
145
+ | `jev(state, condition [, threshold])` | Boolean Noul predicate; default threshold is `0.5` |
146
+ | `jev_prob(state, condition)` | Noul probability from 0 to 1 |
147
+ | `jev_choice(state, question, criteria_json)` | Most likely Choice key |
148
+ | `jev_score(state, question, levels_json)` | Probability-weighted Score level |
149
+ | `jev_score_norm(state, question, levels_json)` | Score normalized to 0 through 1 |
150
+ | `jev_confidence(state, question, kind, criteria_json)` | Choice or Score confidence |
151
+ | `jev_eval(state, question [, kind [, criteria_json]])` | Full answer JSON |
152
+ | `jev_stats()` | Connection-local usage and cache statistics |
153
+ | `jev_cache_clear()` | Clears the connection-local answer cache |
154
+ | `jev_version()` | Extension version |
155
+
156
+ Pass structured state with SQLite JSON functions:
157
+
158
+ ```sql
159
+ SELECT jev_prob(
160
+ json_object('subject', subject, 'message', message),
161
+ 'The customer explicitly expresses urgency'
162
+ )
163
+ FROM tickets
164
+ WHERE id = 42;
165
+ ```
166
+
167
+ ## Configuration
168
+
169
+ Configuration is connection-local:
170
+
171
+ ```sql
172
+ SELECT jev_config('model', 'jev-latest');
173
+ SELECT jev_config('batch_size', 40);
174
+ SELECT jev_config('max_rows', 500);
175
+ SELECT jev_config('timeout', 90);
176
+ SELECT jev_config('api_url', 'https://api.typesafe.ai/v1/systemone');
177
+ SELECT jev_config('api_key', '...');
178
+ ```
179
+
180
+ `max_rows` is a spend guard. A `jev_rows` scan above the limit fails before sending any data.
181
+ The API key is never returned by `jev_config`; it reports only `set` or `unset`.
182
+
183
+ ## Python
184
+
185
+ Add the platform package to a project and load it with the Python wrapper:
186
+
187
+ ```bash
188
+ uv add sqlite-jev
189
+ ```
190
+
191
+ ```python
192
+ import sqlite3
193
+ import sqlite_jev
194
+
195
+ connection = sqlite_jev.load(sqlite3.connect(":memory:"))
196
+ ```
197
+
198
+ The package contains the same native extension as the standalone release, has no runtime
199
+ Python dependencies, and supports maintained Python versions starting with Python 3.10. The
200
+ interpreter's `sqlite3` module must have loadable-extension support enabled.
201
+
202
+ To load a standalone build manually instead:
203
+
204
+ ```python
205
+ import sqlite3
206
+
207
+ connection = sqlite3.connect(":memory:")
208
+ connection.enable_load_extension(True)
209
+ connection.load_extension("/path/to/jev.so") # use jev.dylib on macOS
210
+ connection.enable_load_extension(False)
211
+
212
+ version = connection.execute("select jev_version()").fetchone()[0]
213
+ ```
214
+
215
+ ## Demo and tests
216
+
217
+ The deterministic suite uses a local mock server and never calls TypeSafe:
218
+
219
+ ```bash
220
+ make test
221
+ ```
222
+
223
+ The ticket-triage demo makes two live API requests, one for urgency and one for routing:
224
+
225
+ ```bash
226
+ make live-test
227
+ ```
228
+
229
+ See [`examples/ticket_triage.sql`](examples/ticket_triage.sql) for the complete query.
230
+
231
+ `make integration-test` runs a smaller live smoke test. In GitHub Actions it runs once every
232
+ two months and on manual dispatch using the `TYPESAFE_API_KEY` repository secret. It checks the API contract,
233
+ batching, and answer shapes; semantic expectations remain in the deterministic mock suite so
234
+ normal model variation cannot make pull requests flaky.
235
+
236
+ ## Releases
237
+
238
+ Tags named `vX.Y.Z` build and publish four archives through GitHub Actions:
239
+
240
+ - Linux x86_64 and arm64
241
+ - macOS Intel and Apple Silicon
242
+
243
+ Each archive contains the native extension, this README, and its `pyproject.toml`. The release
244
+ also includes a `py3-none-<platform>` Python wheel and `SHA256SUMS`. CI installs each wheel
245
+ with `cibuildwheel` and verifies that `sqlite_jev.load()` enables the SQL API. The same tag
246
+ publishes the wheels and source distribution to PyPI through trusted publishing.
247
+
248
+ ## Important limits
249
+
250
+ - Row contents are sent to TypeSafe. Do not evaluate data you are not allowed to share.
251
+ - This is a semantic full scan, not an index. Apply deterministic SQLite filters first and
252
+ materialize a small candidate table.
253
+ - Cache entries live only for the current database connection and are keyed by row content,
254
+ model, question, primitive, and criteria.
255
+ - Jev should make narrow judgments. Keep counting, arithmetic, and date comparison in SQL.
256
+ - Text stored in a row can steer model behavior. Test adversarial content and use conservative
257
+ probability or confidence thresholds before automating consequential actions.
258
+ - `libcurl` is loaded dynamically so building does not require the curl development headers.
259
+ Linux and macOS are the currently tested platforms.
@@ -0,0 +1,5 @@
1
+ sqlite_jev-0.1.0.dist-info/RECORD,,
2
+ sqlite_jev-0.1.0.dist-info/WHEEL,sha256=1Big0Cn6LCpgYnkzxn-ESHZfABrxq9SG62kfQRLXJmA,137
3
+ sqlite_jev-0.1.0.dist-info/METADATA,sha256=ihtNpzR6P8GNEGcbDfq81gm-qyg9vaTvMDhlnOvS1aI,8305
4
+ sqlite_jev/__init__.py,sha256=SmhoCPFviB50zSRt-0dfCrQX71C8NuG-e7qQiihijVY,858
5
+ sqlite_jev/jev.dylib,sha256=aNBnNhHbiOJKF9CtRw0aTZy7HYYBXVwKa4422gll-Us,69880
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: scikit-build-core 1.0.3
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-macosx_11_0_arm64
5
+ Generator: delocate 0.13.0
6
+