semantic-python 0.1.0a1__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.
- semantic_python-0.1.0a1/.github/workflows/ci.yml +56 -0
- semantic_python-0.1.0a1/.github/workflows/release.yml +38 -0
- semantic_python-0.1.0a1/.gitignore +18 -0
- semantic_python-0.1.0a1/CHANGELOG.md +20 -0
- semantic_python-0.1.0a1/CONTRIBUTING.md +26 -0
- semantic_python-0.1.0a1/LICENSE +21 -0
- semantic_python-0.1.0a1/PKG-INFO +228 -0
- semantic_python-0.1.0a1/README.md +192 -0
- semantic_python-0.1.0a1/SECURITY.md +10 -0
- semantic_python-0.1.0a1/TODO.md +14 -0
- semantic_python-0.1.0a1/docs/assets/social-preview.png +0 -0
- semantic_python-0.1.0a1/docs/backends.md +90 -0
- semantic_python-0.1.0a1/docs/design.md +60 -0
- semantic_python-0.1.0a1/docs/laya-verification.md +32 -0
- semantic_python-0.1.0a1/docs/roadmap.md +51 -0
- semantic_python-0.1.0a1/docs/semantics.md +47 -0
- semantic_python-0.1.0a1/docs/uncertainty.md +33 -0
- semantic_python-0.1.0a1/examples/escalation.py +33 -0
- semantic_python-0.1.0a1/examples/python_primitives_demo.ipynb +319 -0
- semantic_python-0.1.0a1/examples/semantic_python_demo.ipynb +209 -0
- semantic_python-0.1.0a1/examples/stop_loop.py +33 -0
- semantic_python-0.1.0a1/examples/ticket_routing.py +38 -0
- semantic_python-0.1.0a1/pyproject.toml +101 -0
- semantic_python-0.1.0a1/src/semantic_python/__init__.py +50 -0
- semantic_python-0.1.0a1/src/semantic_python/backends/__init__.py +12 -0
- semantic_python-0.1.0a1/src/semantic_python/backends/base.py +31 -0
- semantic_python-0.1.0a1/src/semantic_python/backends/fake.py +66 -0
- semantic_python-0.1.0a1/src/semantic_python/backends/laya.py +75 -0
- semantic_python-0.1.0a1/src/semantic_python/backends/openai.py +118 -0
- semantic_python-0.1.0a1/src/semantic_python/cache.py +46 -0
- semantic_python-0.1.0a1/src/semantic_python/config.py +101 -0
- semantic_python-0.1.0a1/src/semantic_python/decision.py +125 -0
- semantic_python-0.1.0a1/src/semantic_python/py.typed +1 -0
- semantic_python-0.1.0a1/src/semantic_python/replay.py +80 -0
- semantic_python-0.1.0a1/src/semantic_python/semantic.py +80 -0
- semantic_python-0.1.0a1/tests/conftest.py +13 -0
- semantic_python-0.1.0a1/tests/test_cache_and_replay.py +118 -0
- semantic_python-0.1.0a1/tests/test_laya_backend.py +55 -0
- semantic_python-0.1.0a1/tests/test_live_backends.py +23 -0
- semantic_python-0.1.0a1/tests/test_openai_backend.py +63 -0
- semantic_python-0.1.0a1/tests/test_semantic.py +175 -0
- semantic_python-0.1.0a1/uv.lock +3301 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
strategy:
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v7
|
|
20
|
+
- uses: actions/setup-python@v7
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
cache: pip
|
|
24
|
+
- run: python -m pip install --upgrade pip
|
|
25
|
+
- run: python -m pip install -e '.[dev]'
|
|
26
|
+
- run: pytest --cov=semantic_python --cov-report=term-missing
|
|
27
|
+
|
|
28
|
+
quality:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v7
|
|
32
|
+
- uses: actions/setup-python@v7
|
|
33
|
+
with:
|
|
34
|
+
python-version: "3.12"
|
|
35
|
+
cache: pip
|
|
36
|
+
- run: python -m pip install --upgrade pip
|
|
37
|
+
- run: python -m pip install -e '.[dev]'
|
|
38
|
+
- run: ruff check .
|
|
39
|
+
- run: ruff format --check .
|
|
40
|
+
- run: mypy
|
|
41
|
+
- run: python -m build
|
|
42
|
+
- run: python -m twine check dist/*
|
|
43
|
+
- name: Reject private or workspace-only files in the source archive
|
|
44
|
+
run: |
|
|
45
|
+
if tar -tf dist/*.tar.gz | grep -E '/(AGENTS|REQUIREMENTS)\.md$|/\.vscode/|/\.ipynb_checkpoints/'; then
|
|
46
|
+
echo "Source distribution contains a private or workspace-only file."
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
- name: Verify clean wheel installation and offline examples
|
|
50
|
+
run: |
|
|
51
|
+
python -m venv /tmp/semantic-python-clean
|
|
52
|
+
/tmp/semantic-python-clean/bin/python -m pip install --no-deps dist/*.whl
|
|
53
|
+
cd /tmp
|
|
54
|
+
/tmp/semantic-python-clean/bin/python "$GITHUB_WORKSPACE/examples/stop_loop.py"
|
|
55
|
+
/tmp/semantic-python-clean/bin/python "$GITHUB_WORKSPACE/examples/ticket_routing.py"
|
|
56
|
+
/tmp/semantic-python-clean/bin/python "$GITHUB_WORKSPACE/examples/escalation.py"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v7
|
|
15
|
+
- uses: actions/setup-python@v7
|
|
16
|
+
with:
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
cache: pip
|
|
19
|
+
- run: python -m pip install --upgrade pip build twine
|
|
20
|
+
- run: python -m build
|
|
21
|
+
- run: python -m twine check dist/*
|
|
22
|
+
- uses: actions/upload-artifact@v4
|
|
23
|
+
with:
|
|
24
|
+
name: python-package-distributions
|
|
25
|
+
path: dist/
|
|
26
|
+
|
|
27
|
+
publish:
|
|
28
|
+
needs: build
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
environment: pypi
|
|
31
|
+
permissions:
|
|
32
|
+
id-token: write
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/download-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: python-package-distributions
|
|
37
|
+
path: dist/
|
|
38
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes will be documented here.
|
|
4
|
+
|
|
5
|
+
## [0.1.0a1] - 2026-10-07
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Initial experimental `Semantic[str]` runtime.
|
|
10
|
+
- Inspectable, bool-coercible decisions with explicit uncertainty handling.
|
|
11
|
+
- Deterministic fake backend, caching, and offline record/replay support.
|
|
12
|
+
- Experimental Laya 0.4 and OpenAI backend adapters with explicit data-egress
|
|
13
|
+
documentation.
|
|
14
|
+
- Polished offline examples and opt-in OpenAI notebooks.
|
|
15
|
+
- Python 3.10 through 3.13 testing, strict typing, and release artifact validation.
|
|
16
|
+
|
|
17
|
+
### Security
|
|
18
|
+
|
|
19
|
+
- Raw semantic state is excluded from decision recordings.
|
|
20
|
+
- Hosted credentials are loaded from environment or secure runtime configuration.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Semantic Python is experimental. Open an issue before proposing changes to public semantics.
|
|
4
|
+
|
|
5
|
+
## Development
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
python -m venv .venv
|
|
9
|
+
source .venv/bin/activate
|
|
10
|
+
python -m pip install -e '.[dev]'
|
|
11
|
+
pytest
|
|
12
|
+
ruff check .
|
|
13
|
+
ruff format --check .
|
|
14
|
+
mypy
|
|
15
|
+
python -m build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Keep changes small, add offline tests for behavioral changes, and never require paid credentials in the default test suite. Live provider tests must be explicitly opted into.
|
|
19
|
+
|
|
20
|
+
## Design changes
|
|
21
|
+
|
|
22
|
+
Changes to equality, truthiness, uncertainty, privacy, or backend behavior need a written rationale and documentation. Ordinary non-semantic Python behavior must remain untouched.
|
|
23
|
+
|
|
24
|
+
## Security and privacy
|
|
25
|
+
|
|
26
|
+
Do not commit credentials or fixtures containing private user input. Prefer hashed or redacted state in logs and bug reports.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Semantic Python contributors
|
|
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,228 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: semantic-python
|
|
3
|
+
Version: 0.1.0a1
|
|
4
|
+
Summary: Experimental semantic values for Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/SaiRiteshThela/semantic-python
|
|
6
|
+
Project-URL: Repository, https://github.com/SaiRiteshThela/semantic-python
|
|
7
|
+
Project-URL: Issues, https://github.com/SaiRiteshThela/semantic-python/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/SaiRiteshThela/semantic-python/blob/main/CHANGELOG.md
|
|
9
|
+
Author: Sai Ritesh Thela
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: ai,decision-models,python,semantic
|
|
13
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build>=1.2; extra == 'dev'
|
|
24
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=8.3; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
28
|
+
Requires-Dist: twine>=6.0; extra == 'dev'
|
|
29
|
+
Provides-Extra: laya
|
|
30
|
+
Requires-Dist: laya<0.5,>=0.4.0; extra == 'laya'
|
|
31
|
+
Provides-Extra: notebook
|
|
32
|
+
Requires-Dist: ipykernel>=6.29; extra == 'notebook'
|
|
33
|
+
Provides-Extra: openai
|
|
34
|
+
Requires-Dist: openai<3,>=2; extra == 'openai'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# Semantic Python
|
|
38
|
+
|
|
39
|
+
> Python, but `==` can understand meaning.
|
|
40
|
+
|
|
41
|
+
Semantic Python is not a model like Laya or Jev. It is an opt-in Python value
|
|
42
|
+
layer that turns backend inference into inspectable decisions for normal Python
|
|
43
|
+
control flow. Only `Semantic(...)` values can invoke a model.
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
python -m pip install 'semantic-python[openai]'
|
|
49
|
+
export OPENAI_API_KEY="..."
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Demo
|
|
53
|
+
|
|
54
|
+
Use natural-language intent in ordinary loops and async code:
|
|
55
|
+
|
|
56
|
+
`functions` · `if` · `try/except` · `for` · `while` · `comprehensions` ·
|
|
57
|
+
`generators` · `classes` · `with` · `async/await`
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
import asyncio
|
|
61
|
+
|
|
62
|
+
from semantic_python import (
|
|
63
|
+
OpenAIBackend,
|
|
64
|
+
Semantic,
|
|
65
|
+
UncertainDecisionError,
|
|
66
|
+
configure,
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
STOP = "the user wants to stop"
|
|
70
|
+
|
|
71
|
+
configure(
|
|
72
|
+
backend=OpenAIBackend(model="gpt-6-luna"),
|
|
73
|
+
true_threshold=0.85,
|
|
74
|
+
false_threshold=0.15,
|
|
75
|
+
uncertainty="raise",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def decide(text: str):
|
|
80
|
+
return Semantic(text) == STOP
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
messages = [
|
|
84
|
+
"Continue with the next ticket.",
|
|
85
|
+
"Save the work and close this session.",
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
for text in messages:
|
|
89
|
+
decision = decide(text)
|
|
90
|
+
print(f"stop={decision.value} p={decision.probability:.2f} model={decision.model}")
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
if decision:
|
|
94
|
+
print("Stop requested")
|
|
95
|
+
break
|
|
96
|
+
except UncertainDecisionError:
|
|
97
|
+
print("Send to human review")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
async def decide_async(text: str):
|
|
101
|
+
return await asyncio.to_thread(decide, text)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
async_result = asyncio.run(decide_async(text))
|
|
105
|
+
opposite = Semantic(text) != STOP
|
|
106
|
+
|
|
107
|
+
print("async cache hit:", async_result.cached)
|
|
108
|
+
print("negated:", opposite.value, opposite.probability)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
The comparison returns a bool-coercible `Decision`, so `if` and loops work
|
|
112
|
+
normally while probability, model provenance, caching, and replay remain
|
|
113
|
+
available. `!=` negates the same judgment instead of issuing a second inference.
|
|
114
|
+
|
|
115
|
+
## More Python patterns
|
|
116
|
+
|
|
117
|
+
These examples continue with the configured backend and `STOP` proposition from
|
|
118
|
+
the main demo.
|
|
119
|
+
|
|
120
|
+
### `while`
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
queue = iter(["Keep going", "Not yet", "Finished for today"])
|
|
124
|
+
message = Semantic(next(queue))
|
|
125
|
+
|
|
126
|
+
while message != STOP:
|
|
127
|
+
print("Processing:", message.value)
|
|
128
|
+
message = Semantic(next(queue))
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Comprehensions and generators
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
texts = ["Continue", "Pause here", "That is all for today"]
|
|
135
|
+
decisions = {text: decide(text) for text in texts}
|
|
136
|
+
|
|
137
|
+
stop_requests = [text for text, decision in decisions.items() if decision.value]
|
|
138
|
+
|
|
139
|
+
probabilities = (decision.probability for decision in decisions.values())
|
|
140
|
+
print(stop_requests, list(probabilities))
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Classes
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
from dataclasses import dataclass
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@dataclass(frozen=True, slots=True)
|
|
150
|
+
class IntentRule:
|
|
151
|
+
proposition: str
|
|
152
|
+
|
|
153
|
+
def evaluate(self, text: str):
|
|
154
|
+
return Semantic(text) == self.proposition
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
stop_rule = IntentRule("the user wants to stop")
|
|
158
|
+
decision = stop_rule.evaluate("Please close the session")
|
|
159
|
+
print(decision.value, decision.probability)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Context managers and offline tests
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
from semantic_python import FakeBackend, configuration
|
|
166
|
+
|
|
167
|
+
state = "I'm done"
|
|
168
|
+
fixtures = {(state, STOP): (True, 0.99)}
|
|
169
|
+
|
|
170
|
+
with configuration(backend=FakeBackend(fixtures), cache=False):
|
|
171
|
+
assert Semantic(state) == STOP
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Backends
|
|
175
|
+
|
|
176
|
+
Application code stays the same when the configured backend changes.
|
|
177
|
+
|
|
178
|
+
| Backend | Install | Purpose |
|
|
179
|
+
| --- | --- | --- |
|
|
180
|
+
| `OpenAIBackend` | `semantic-python[openai]` | Hosted inference |
|
|
181
|
+
| `LayaBackend` | `semantic-python[laya]` | Local inference |
|
|
182
|
+
| `FakeBackend` | Included | Deterministic offline tests |
|
|
183
|
+
|
|
184
|
+
OpenAI receives the wrapped state and proposition. Laya may download model
|
|
185
|
+
checkpoints on first use. FakeBackend performs no network requests.
|
|
186
|
+
|
|
187
|
+
## Semantics
|
|
188
|
+
|
|
189
|
+
| Expression | Result |
|
|
190
|
+
| --- | --- |
|
|
191
|
+
| `plain_string == other` | Ordinary Python equality |
|
|
192
|
+
| `Semantic(text) == proposition` | Inspectable semantic `Decision` |
|
|
193
|
+
| `Semantic(text) != proposition` | Negated cached judgment |
|
|
194
|
+
| `semantic is other` | Ordinary Python identity |
|
|
195
|
+
| `Semantic(...) == Semantic(...)` | Rejected as ambiguous |
|
|
196
|
+
| `hash(Semantic(...))` | Rejected; inference is never used for hashing |
|
|
197
|
+
|
|
198
|
+
Probabilities at or above `0.85` resolve true, probabilities at or below `0.15`
|
|
199
|
+
resolve false, and the default policy raises `UncertainDecisionError` between
|
|
200
|
+
those thresholds. Backend failures are raised rather than converted to `False`.
|
|
201
|
+
|
|
202
|
+
## Examples
|
|
203
|
+
|
|
204
|
+
- [OpenAI demo](examples/semantic_python_demo.ipynb)
|
|
205
|
+
- [Python control-flow demo](examples/python_primitives_demo.ipynb)
|
|
206
|
+
- [Stop loop](examples/stop_loop.py)
|
|
207
|
+
- [Ticket routing](examples/ticket_routing.py)
|
|
208
|
+
- [Uncertainty and escalation](examples/escalation.py)
|
|
209
|
+
|
|
210
|
+
The offline examples run without credentials:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
python -m pip install -e .
|
|
214
|
+
python examples/stop_loop.py
|
|
215
|
+
python examples/ticket_routing.py
|
|
216
|
+
python examples/escalation.py
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Safety
|
|
220
|
+
|
|
221
|
+
- Model probability is an estimate, not truth or authorization.
|
|
222
|
+
- Hosted inference can transmit sensitive text and incur cost.
|
|
223
|
+
- Consequential actions should use conservative thresholds and human review.
|
|
224
|
+
|
|
225
|
+
See [semantics](docs/semantics.md), [backends](docs/backends.md), and
|
|
226
|
+
[uncertainty](docs/uncertainty.md) for the complete behavior.
|
|
227
|
+
|
|
228
|
+
MIT licensed. Experimental and pre-alpha.
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# Semantic Python
|
|
2
|
+
|
|
3
|
+
> Python, but `==` can understand meaning.
|
|
4
|
+
|
|
5
|
+
Semantic Python is not a model like Laya or Jev. It is an opt-in Python value
|
|
6
|
+
layer that turns backend inference into inspectable decisions for normal Python
|
|
7
|
+
control flow. Only `Semantic(...)` values can invoke a model.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
python -m pip install 'semantic-python[openai]'
|
|
13
|
+
export OPENAI_API_KEY="..."
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Demo
|
|
17
|
+
|
|
18
|
+
Use natural-language intent in ordinary loops and async code:
|
|
19
|
+
|
|
20
|
+
`functions` · `if` · `try/except` · `for` · `while` · `comprehensions` ·
|
|
21
|
+
`generators` · `classes` · `with` · `async/await`
|
|
22
|
+
|
|
23
|
+
```python
|
|
24
|
+
import asyncio
|
|
25
|
+
|
|
26
|
+
from semantic_python import (
|
|
27
|
+
OpenAIBackend,
|
|
28
|
+
Semantic,
|
|
29
|
+
UncertainDecisionError,
|
|
30
|
+
configure,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
STOP = "the user wants to stop"
|
|
34
|
+
|
|
35
|
+
configure(
|
|
36
|
+
backend=OpenAIBackend(model="gpt-6-luna"),
|
|
37
|
+
true_threshold=0.85,
|
|
38
|
+
false_threshold=0.15,
|
|
39
|
+
uncertainty="raise",
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def decide(text: str):
|
|
44
|
+
return Semantic(text) == STOP
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
messages = [
|
|
48
|
+
"Continue with the next ticket.",
|
|
49
|
+
"Save the work and close this session.",
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
for text in messages:
|
|
53
|
+
decision = decide(text)
|
|
54
|
+
print(f"stop={decision.value} p={decision.probability:.2f} model={decision.model}")
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
if decision:
|
|
58
|
+
print("Stop requested")
|
|
59
|
+
break
|
|
60
|
+
except UncertainDecisionError:
|
|
61
|
+
print("Send to human review")
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
async def decide_async(text: str):
|
|
65
|
+
return await asyncio.to_thread(decide, text)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
async_result = asyncio.run(decide_async(text))
|
|
69
|
+
opposite = Semantic(text) != STOP
|
|
70
|
+
|
|
71
|
+
print("async cache hit:", async_result.cached)
|
|
72
|
+
print("negated:", opposite.value, opposite.probability)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The comparison returns a bool-coercible `Decision`, so `if` and loops work
|
|
76
|
+
normally while probability, model provenance, caching, and replay remain
|
|
77
|
+
available. `!=` negates the same judgment instead of issuing a second inference.
|
|
78
|
+
|
|
79
|
+
## More Python patterns
|
|
80
|
+
|
|
81
|
+
These examples continue with the configured backend and `STOP` proposition from
|
|
82
|
+
the main demo.
|
|
83
|
+
|
|
84
|
+
### `while`
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
queue = iter(["Keep going", "Not yet", "Finished for today"])
|
|
88
|
+
message = Semantic(next(queue))
|
|
89
|
+
|
|
90
|
+
while message != STOP:
|
|
91
|
+
print("Processing:", message.value)
|
|
92
|
+
message = Semantic(next(queue))
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Comprehensions and generators
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
texts = ["Continue", "Pause here", "That is all for today"]
|
|
99
|
+
decisions = {text: decide(text) for text in texts}
|
|
100
|
+
|
|
101
|
+
stop_requests = [text for text, decision in decisions.items() if decision.value]
|
|
102
|
+
|
|
103
|
+
probabilities = (decision.probability for decision in decisions.values())
|
|
104
|
+
print(stop_requests, list(probabilities))
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Classes
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from dataclasses import dataclass
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@dataclass(frozen=True, slots=True)
|
|
114
|
+
class IntentRule:
|
|
115
|
+
proposition: str
|
|
116
|
+
|
|
117
|
+
def evaluate(self, text: str):
|
|
118
|
+
return Semantic(text) == self.proposition
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
stop_rule = IntentRule("the user wants to stop")
|
|
122
|
+
decision = stop_rule.evaluate("Please close the session")
|
|
123
|
+
print(decision.value, decision.probability)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Context managers and offline tests
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from semantic_python import FakeBackend, configuration
|
|
130
|
+
|
|
131
|
+
state = "I'm done"
|
|
132
|
+
fixtures = {(state, STOP): (True, 0.99)}
|
|
133
|
+
|
|
134
|
+
with configuration(backend=FakeBackend(fixtures), cache=False):
|
|
135
|
+
assert Semantic(state) == STOP
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Backends
|
|
139
|
+
|
|
140
|
+
Application code stays the same when the configured backend changes.
|
|
141
|
+
|
|
142
|
+
| Backend | Install | Purpose |
|
|
143
|
+
| --- | --- | --- |
|
|
144
|
+
| `OpenAIBackend` | `semantic-python[openai]` | Hosted inference |
|
|
145
|
+
| `LayaBackend` | `semantic-python[laya]` | Local inference |
|
|
146
|
+
| `FakeBackend` | Included | Deterministic offline tests |
|
|
147
|
+
|
|
148
|
+
OpenAI receives the wrapped state and proposition. Laya may download model
|
|
149
|
+
checkpoints on first use. FakeBackend performs no network requests.
|
|
150
|
+
|
|
151
|
+
## Semantics
|
|
152
|
+
|
|
153
|
+
| Expression | Result |
|
|
154
|
+
| --- | --- |
|
|
155
|
+
| `plain_string == other` | Ordinary Python equality |
|
|
156
|
+
| `Semantic(text) == proposition` | Inspectable semantic `Decision` |
|
|
157
|
+
| `Semantic(text) != proposition` | Negated cached judgment |
|
|
158
|
+
| `semantic is other` | Ordinary Python identity |
|
|
159
|
+
| `Semantic(...) == Semantic(...)` | Rejected as ambiguous |
|
|
160
|
+
| `hash(Semantic(...))` | Rejected; inference is never used for hashing |
|
|
161
|
+
|
|
162
|
+
Probabilities at or above `0.85` resolve true, probabilities at or below `0.15`
|
|
163
|
+
resolve false, and the default policy raises `UncertainDecisionError` between
|
|
164
|
+
those thresholds. Backend failures are raised rather than converted to `False`.
|
|
165
|
+
|
|
166
|
+
## Examples
|
|
167
|
+
|
|
168
|
+
- [OpenAI demo](examples/semantic_python_demo.ipynb)
|
|
169
|
+
- [Python control-flow demo](examples/python_primitives_demo.ipynb)
|
|
170
|
+
- [Stop loop](examples/stop_loop.py)
|
|
171
|
+
- [Ticket routing](examples/ticket_routing.py)
|
|
172
|
+
- [Uncertainty and escalation](examples/escalation.py)
|
|
173
|
+
|
|
174
|
+
The offline examples run without credentials:
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
python -m pip install -e .
|
|
178
|
+
python examples/stop_loop.py
|
|
179
|
+
python examples/ticket_routing.py
|
|
180
|
+
python examples/escalation.py
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Safety
|
|
184
|
+
|
|
185
|
+
- Model probability is an estimate, not truth or authorization.
|
|
186
|
+
- Hosted inference can transmit sensitive text and incur cost.
|
|
187
|
+
- Consequential actions should use conservative thresholds and human review.
|
|
188
|
+
|
|
189
|
+
See [semantics](docs/semantics.md), [backends](docs/backends.md), and
|
|
190
|
+
[uncertainty](docs/uncertainty.md) for the complete behavior.
|
|
191
|
+
|
|
192
|
+
MIT licensed. Experimental and pre-alpha.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
This pre-alpha project is not ready for high-impact authorization decisions or untrusted production workloads.
|
|
4
|
+
|
|
5
|
+
Report suspected vulnerabilities through the repository's private security-advisory
|
|
6
|
+
form. Do not open a public issue containing exploit details, credentials, or user
|
|
7
|
+
data. If private reporting is unavailable, contact the package owner through the
|
|
8
|
+
maintainer controls on PyPI before sharing technical details.
|
|
9
|
+
|
|
10
|
+
Remote backends may transmit wrapped semantic state outside the process. Applications must disclose and configure that behavior explicitly. Never commit provider credentials; use environment-based or secure runtime configuration.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# TODO
|
|
2
|
+
|
|
3
|
+
## After v0.1
|
|
4
|
+
|
|
5
|
+
- Evaluate and, if justified, add a Jev hosted-backend adapter.
|
|
6
|
+
- Evaluate Kev as an additional local/self-hosted backend.
|
|
7
|
+
- Evaluate AnyJev as a research adapter path.
|
|
8
|
+
- Define a stable public custom-backend registration API.
|
|
9
|
+
- Add configurable retry, timeout, and cost-budget controls for hosted providers.
|
|
10
|
+
- Add cross-backend conformance tests and reproducible quality/calibration benchmarks.
|
|
11
|
+
|
|
12
|
+
These items are deliberately outside v0.1. Laya remains the primary local backend,
|
|
13
|
+
OpenAI remains an explicitly selected experimental hosted backend, and `FakeBackend`
|
|
14
|
+
exists for deterministic offline development, examples, and tests.
|
|
Binary file
|