superii-sdk 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.
- superii_sdk-0.1.0/.gitignore +44 -0
- superii_sdk-0.1.0/LICENSE +13 -0
- superii_sdk-0.1.0/PKG-INFO +146 -0
- superii_sdk-0.1.0/README.md +115 -0
- superii_sdk-0.1.0/pyproject.toml +39 -0
- superii_sdk-0.1.0/src/superii/__init__.py +84 -0
- superii_sdk-0.1.0/src/superii/attestation.py +39 -0
- superii_sdk-0.1.0/src/superii/cli.py +77 -0
- superii_sdk-0.1.0/src/superii/client.py +323 -0
- superii_sdk-0.1.0/src/superii/errors.py +10 -0
- superii_sdk-0.1.0/src/superii/experiments.py +137 -0
- superii_sdk-0.1.0/src/superii/hardware.py +75 -0
- superii_sdk-0.1.0/src/superii/manifest.py +122 -0
- superii_sdk-0.1.0/src/superii/model.py +337 -0
- superii_sdk-0.1.0/src/superii/planner.py +183 -0
- superii_sdk-0.1.0/src/superii/py.typed +0 -0
- superii_sdk-0.1.0/src/superii/remote.py +76 -0
- superii_sdk-0.1.0/src/superii/serving.py +191 -0
- superii_sdk-0.1.0/tests/test_experiments.py +100 -0
- superii_sdk-0.1.0/tests/test_mcp.py +37 -0
- superii_sdk-0.1.0/tests/test_sdk.py +315 -0
- superii_sdk-0.1.0/uv.lock +1972 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# build output
|
|
2
|
+
dist/
|
|
3
|
+
# generated types
|
|
4
|
+
.astro/
|
|
5
|
+
|
|
6
|
+
# dependencies
|
|
7
|
+
node_modules/
|
|
8
|
+
|
|
9
|
+
# local Cloudflare deployment state
|
|
10
|
+
.wrangler/
|
|
11
|
+
|
|
12
|
+
# logs
|
|
13
|
+
npm-debug.log*
|
|
14
|
+
yarn-debug.log*
|
|
15
|
+
yarn-error.log*
|
|
16
|
+
pnpm-debug.log*
|
|
17
|
+
|
|
18
|
+
# Python bytecode
|
|
19
|
+
__pycache__/
|
|
20
|
+
*.py[cod]
|
|
21
|
+
.pytest_cache/
|
|
22
|
+
.ruff_cache/
|
|
23
|
+
.venv/
|
|
24
|
+
|
|
25
|
+
# Super ii Runtime local state (uploads and generated artifacts never enter Git)
|
|
26
|
+
runtime/data/
|
|
27
|
+
runtime/workspaces/
|
|
28
|
+
rust/target/
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# environment variables
|
|
32
|
+
.env
|
|
33
|
+
.env.*
|
|
34
|
+
.dev.vars
|
|
35
|
+
!.env.example
|
|
36
|
+
|
|
37
|
+
# local visual QA captures (the written QA record remains tracked)
|
|
38
|
+
qa/evidence/
|
|
39
|
+
|
|
40
|
+
# macOS-specific files
|
|
41
|
+
.DS_Store
|
|
42
|
+
|
|
43
|
+
# jetbrains setting folder
|
|
44
|
+
.idea/
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Modified MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Super ii
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
10
|
+
|
|
11
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
12
|
+
|
|
13
|
+
Our only modification part is that, if the Software (or any derivative works thereof) is used for any of your commercial products or services that have more than 1000 monthly active users, or more than 10000 US dollars (or equivalent in other currencies) in monthly revenue, you shall at all times prominently display "www.superii.site" on the user interface of such product or service.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: superii-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Verified Super ii model acquisition, hardware planning and local inference
|
|
5
|
+
Project-URL: Homepage, https://superii.site
|
|
6
|
+
Project-URL: Source, https://github.com/smavgs/super-ii/tree/main/sdk/python
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Requires-Dist: cryptography<51,>=46
|
|
11
|
+
Requires-Dist: filelock<4,>=3.19
|
|
12
|
+
Requires-Dist: httpx<0.29,>=0.28
|
|
13
|
+
Requires-Dist: psutil<8,>=7
|
|
14
|
+
Provides-Extra: mlx
|
|
15
|
+
Requires-Dist: mlx-lm<1,>=0.30; (sys_platform == 'darwin') and extra == 'mlx'
|
|
16
|
+
Provides-Extra: serve
|
|
17
|
+
Requires-Dist: fastapi<1,>=0.115; extra == 'serve'
|
|
18
|
+
Requires-Dist: mcp<2,>=1.20; extra == 'serve'
|
|
19
|
+
Requires-Dist: uvicorn<1,>=0.35; extra == 'serve'
|
|
20
|
+
Provides-Extra: test
|
|
21
|
+
Requires-Dist: fastapi<1,>=0.115; extra == 'test'
|
|
22
|
+
Requires-Dist: mcp<2,>=1.20; extra == 'test'
|
|
23
|
+
Requires-Dist: pytest<10,>=9; extra == 'test'
|
|
24
|
+
Requires-Dist: ruff<1,>=0.16; extra == 'test'
|
|
25
|
+
Provides-Extra: transformers
|
|
26
|
+
Requires-Dist: accelerate<2,>=1.10; extra == 'transformers'
|
|
27
|
+
Requires-Dist: safetensors<1,>=0.6; extra == 'transformers'
|
|
28
|
+
Requires-Dist: torch<3,>=2.8; extra == 'transformers'
|
|
29
|
+
Requires-Dist: transformers<6,>=5; extra == 'transformers'
|
|
30
|
+
Description-Content-Type: text/markdown
|
|
31
|
+
|
|
32
|
+
# Super ii Python SDK
|
|
33
|
+
|
|
34
|
+
Install the package (Python 3.11 or newer):
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
python -m pip install superii-sdk
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The distribution is named `superii-sdk`; the import and CLI are named `superii`.
|
|
41
|
+
For a source checkout, use `python -m pip install ./sdk/python` instead.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import superii
|
|
45
|
+
|
|
46
|
+
print(superii.hardware()) # stays on this machine
|
|
47
|
+
print(superii.inspect("owner/model")) # metadata, immutable files and evidence
|
|
48
|
+
print(superii.plan("owner/model")) # estimates and explains before loading
|
|
49
|
+
with superii.load("owner/model") as model:
|
|
50
|
+
print(model.generate("Hello", max_tokens=128))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The catalogue remains intentionally empty before creator submissions. The
|
|
54
|
+
example repository is a placeholder, not a seeded or downloadable model.
|
|
55
|
+
|
|
56
|
+
`load` resolves one published commit, plans against available memory, downloads
|
|
57
|
+
only its selected files, verifies every SHA-256, checks memory again and invokes
|
|
58
|
+
an installed runtime. Pass `revision="<full 64-character commit>"` for reproducible
|
|
59
|
+
notebooks, applications, training inputs and CI. `pull` returns a `Snapshot` with
|
|
60
|
+
its path and manifest; `verify(snapshot)` rechecks bytes. `await superii.apull(...)`
|
|
61
|
+
and `Client.prefetch(...)` support asynchronous/background acquisition.
|
|
62
|
+
|
|
63
|
+
Install llama.cpp's `llama-server` from its official distribution for GGUF.
|
|
64
|
+
Optional extras `superii-sdk[mlx]`, `superii-sdk[transformers]` and
|
|
65
|
+
`superii-sdk[serve]` add those integrations;
|
|
66
|
+
install vLLM using its hardware-specific official instructions. Nothing installs
|
|
67
|
+
or recompiles a backend behind the user's back. The initial planner supports
|
|
68
|
+
single-file GGUF and known text architectures with safetensors. Unsupported
|
|
69
|
+
architectures, custom Python, split GGUF and ambiguous conversions fail with a
|
|
70
|
+
reason. The vLLM and Transformers offline adapters currently return a complete
|
|
71
|
+
response rather than token streaming.
|
|
72
|
+
|
|
73
|
+
Memory estimates include OS headroom and context overhead, but are not a zero-OOM
|
|
74
|
+
guarantee. Existing smaller or quantized artifacts are preferred to inventing a
|
|
75
|
+
conversion. GPU support must be present in the installed runtime; compatibility
|
|
76
|
+
metadata is not a benchmark. `lazy_weights=True` enables the installed MLX
|
|
77
|
+
loader's lazy evaluation of already-verified local weights; it does not execute
|
|
78
|
+
partially downloaded weights.
|
|
79
|
+
|
|
80
|
+
Downloads use strict ranges, resume partial chunks, verify the final file and
|
|
81
|
+
deduplicate content within each authenticated cache. Redirects cannot forward
|
|
82
|
+
credentials; private content uses a separate credential-scoped cache. Set
|
|
83
|
+
`SUPERII_TOKEN` to an existing scoped token with `repository:read` to access an
|
|
84
|
+
authorized private published release. Every new pull rechecks canonical access,
|
|
85
|
+
even when bytes are cached. Files already intentionally downloaded by their
|
|
86
|
+
authorized owner remain local; revocation cannot erase an owner's copies.
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
with superii.load("owner/model") as model:
|
|
90
|
+
model.serve(port=8765, token=your_random_local_token) # loopback OpenAI text API
|
|
91
|
+
# Or model.serve_mcp() for a stdio MCP inference tool.
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The OpenAI endpoint requires a token and rejects browser origins. It implements
|
|
95
|
+
non-streaming text completions and chat completions; it does not claim full
|
|
96
|
+
OpenAI API parity. MCP exposes one inference tool and does not itself configure
|
|
97
|
+
an agent's model provider. Repository content and model output remain untrusted.
|
|
98
|
+
|
|
99
|
+
An optional explicit `Client(peers=(Peer("https://cache.example", peer_token),))`
|
|
100
|
+
can use a peer cache. No discovery or LAN broadcasts occur. Private artifacts
|
|
101
|
+
always bypass peers. `superii.serving.create_cache_app` serves already-cached
|
|
102
|
+
public hashes only, after fresh canonical visibility checks. Deploy that optional
|
|
103
|
+
service with TLS and a separate strong peer credential; otherwise leave peers
|
|
104
|
+
unset. Outages, missing data and corrupted peer bytes fall back to the origin.
|
|
105
|
+
|
|
106
|
+
Canonical manifests are hashes, not publisher identity proofs. New automatic
|
|
107
|
+
publication also returns an Ed25519 policy attestation; verification and key
|
|
108
|
+
pinning are documented with the publication service. Historical releases retain
|
|
109
|
+
their historical evidence and are not silently relabeled.
|
|
110
|
+
|
|
111
|
+
## Measurements and acquisition research
|
|
112
|
+
|
|
113
|
+
`superii benchmark owner/model "Hello" --max-tokens 128` records first output,
|
|
114
|
+
generation time, approximate tokens per second, sampled process-tree peak RSS
|
|
115
|
+
and bytes acquired before inference. Batch adapters label first-output time
|
|
116
|
+
separately from token-streaming TTFT. RSS does not measure all GPU allocations.
|
|
117
|
+
Run cold and warm cache trials separately; the tool does not clear the OS cache.
|
|
118
|
+
|
|
119
|
+
`superii.experiments.tensor_ranges(snapshot)` indexes verified safetensors, and
|
|
120
|
+
`iter_tensor_bytes(snapshot, prefix="model.layers.0.")` performs bounded mmap
|
|
121
|
+
reads for layer or expert experiments. These are tested access primitives;
|
|
122
|
+
arbitrary models do not yet execute with partial weights. All files must pass
|
|
123
|
+
full verification first. Quantization/conversion, layer scheduling and MoE
|
|
124
|
+
expert selection require an architecture-specific implementation and benchmark.
|
|
125
|
+
|
|
126
|
+
Optional remote warm-start is explicit at each remote request:
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
from superii.remote import RemoteModel
|
|
130
|
+
|
|
131
|
+
# This call sends the prompt to your chosen provider. Use its separate token.
|
|
132
|
+
# Local pull/load may run concurrently in your application's executor.
|
|
133
|
+
with RemoteModel("https://your-provider.example", "model-id", token=provider_token) as remote:
|
|
134
|
+
answer = remote.generate("Hello")
|
|
135
|
+
# Switch to your completed local Model for later requests when you choose.
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This adapter implements the provider's non-streaming `/v1/completions` contract.
|
|
139
|
+
It never reuses Super ii credentials, follows redirects, silently falls back to
|
|
140
|
+
remote execution, or asserts that remote and local model outputs are identical.
|
|
141
|
+
|
|
142
|
+
Sources: [llama.cpp server](https://github.com/ggml-org/llama.cpp/tree/master/tools/server),
|
|
143
|
+
[MLX LM](https://github.com/ml-explore/mlx-lm),
|
|
144
|
+
[vLLM](https://docs.vllm.ai/en/latest/),
|
|
145
|
+
[safetensors](https://huggingface.co/docs/safetensors/),
|
|
146
|
+
[MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk).
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Super ii Python SDK
|
|
2
|
+
|
|
3
|
+
Install the package (Python 3.11 or newer):
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
python -m pip install superii-sdk
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The distribution is named `superii-sdk`; the import and CLI are named `superii`.
|
|
10
|
+
For a source checkout, use `python -m pip install ./sdk/python` instead.
|
|
11
|
+
|
|
12
|
+
```python
|
|
13
|
+
import superii
|
|
14
|
+
|
|
15
|
+
print(superii.hardware()) # stays on this machine
|
|
16
|
+
print(superii.inspect("owner/model")) # metadata, immutable files and evidence
|
|
17
|
+
print(superii.plan("owner/model")) # estimates and explains before loading
|
|
18
|
+
with superii.load("owner/model") as model:
|
|
19
|
+
print(model.generate("Hello", max_tokens=128))
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The catalogue remains intentionally empty before creator submissions. The
|
|
23
|
+
example repository is a placeholder, not a seeded or downloadable model.
|
|
24
|
+
|
|
25
|
+
`load` resolves one published commit, plans against available memory, downloads
|
|
26
|
+
only its selected files, verifies every SHA-256, checks memory again and invokes
|
|
27
|
+
an installed runtime. Pass `revision="<full 64-character commit>"` for reproducible
|
|
28
|
+
notebooks, applications, training inputs and CI. `pull` returns a `Snapshot` with
|
|
29
|
+
its path and manifest; `verify(snapshot)` rechecks bytes. `await superii.apull(...)`
|
|
30
|
+
and `Client.prefetch(...)` support asynchronous/background acquisition.
|
|
31
|
+
|
|
32
|
+
Install llama.cpp's `llama-server` from its official distribution for GGUF.
|
|
33
|
+
Optional extras `superii-sdk[mlx]`, `superii-sdk[transformers]` and
|
|
34
|
+
`superii-sdk[serve]` add those integrations;
|
|
35
|
+
install vLLM using its hardware-specific official instructions. Nothing installs
|
|
36
|
+
or recompiles a backend behind the user's back. The initial planner supports
|
|
37
|
+
single-file GGUF and known text architectures with safetensors. Unsupported
|
|
38
|
+
architectures, custom Python, split GGUF and ambiguous conversions fail with a
|
|
39
|
+
reason. The vLLM and Transformers offline adapters currently return a complete
|
|
40
|
+
response rather than token streaming.
|
|
41
|
+
|
|
42
|
+
Memory estimates include OS headroom and context overhead, but are not a zero-OOM
|
|
43
|
+
guarantee. Existing smaller or quantized artifacts are preferred to inventing a
|
|
44
|
+
conversion. GPU support must be present in the installed runtime; compatibility
|
|
45
|
+
metadata is not a benchmark. `lazy_weights=True` enables the installed MLX
|
|
46
|
+
loader's lazy evaluation of already-verified local weights; it does not execute
|
|
47
|
+
partially downloaded weights.
|
|
48
|
+
|
|
49
|
+
Downloads use strict ranges, resume partial chunks, verify the final file and
|
|
50
|
+
deduplicate content within each authenticated cache. Redirects cannot forward
|
|
51
|
+
credentials; private content uses a separate credential-scoped cache. Set
|
|
52
|
+
`SUPERII_TOKEN` to an existing scoped token with `repository:read` to access an
|
|
53
|
+
authorized private published release. Every new pull rechecks canonical access,
|
|
54
|
+
even when bytes are cached. Files already intentionally downloaded by their
|
|
55
|
+
authorized owner remain local; revocation cannot erase an owner's copies.
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
with superii.load("owner/model") as model:
|
|
59
|
+
model.serve(port=8765, token=your_random_local_token) # loopback OpenAI text API
|
|
60
|
+
# Or model.serve_mcp() for a stdio MCP inference tool.
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The OpenAI endpoint requires a token and rejects browser origins. It implements
|
|
64
|
+
non-streaming text completions and chat completions; it does not claim full
|
|
65
|
+
OpenAI API parity. MCP exposes one inference tool and does not itself configure
|
|
66
|
+
an agent's model provider. Repository content and model output remain untrusted.
|
|
67
|
+
|
|
68
|
+
An optional explicit `Client(peers=(Peer("https://cache.example", peer_token),))`
|
|
69
|
+
can use a peer cache. No discovery or LAN broadcasts occur. Private artifacts
|
|
70
|
+
always bypass peers. `superii.serving.create_cache_app` serves already-cached
|
|
71
|
+
public hashes only, after fresh canonical visibility checks. Deploy that optional
|
|
72
|
+
service with TLS and a separate strong peer credential; otherwise leave peers
|
|
73
|
+
unset. Outages, missing data and corrupted peer bytes fall back to the origin.
|
|
74
|
+
|
|
75
|
+
Canonical manifests are hashes, not publisher identity proofs. New automatic
|
|
76
|
+
publication also returns an Ed25519 policy attestation; verification and key
|
|
77
|
+
pinning are documented with the publication service. Historical releases retain
|
|
78
|
+
their historical evidence and are not silently relabeled.
|
|
79
|
+
|
|
80
|
+
## Measurements and acquisition research
|
|
81
|
+
|
|
82
|
+
`superii benchmark owner/model "Hello" --max-tokens 128` records first output,
|
|
83
|
+
generation time, approximate tokens per second, sampled process-tree peak RSS
|
|
84
|
+
and bytes acquired before inference. Batch adapters label first-output time
|
|
85
|
+
separately from token-streaming TTFT. RSS does not measure all GPU allocations.
|
|
86
|
+
Run cold and warm cache trials separately; the tool does not clear the OS cache.
|
|
87
|
+
|
|
88
|
+
`superii.experiments.tensor_ranges(snapshot)` indexes verified safetensors, and
|
|
89
|
+
`iter_tensor_bytes(snapshot, prefix="model.layers.0.")` performs bounded mmap
|
|
90
|
+
reads for layer or expert experiments. These are tested access primitives;
|
|
91
|
+
arbitrary models do not yet execute with partial weights. All files must pass
|
|
92
|
+
full verification first. Quantization/conversion, layer scheduling and MoE
|
|
93
|
+
expert selection require an architecture-specific implementation and benchmark.
|
|
94
|
+
|
|
95
|
+
Optional remote warm-start is explicit at each remote request:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from superii.remote import RemoteModel
|
|
99
|
+
|
|
100
|
+
# This call sends the prompt to your chosen provider. Use its separate token.
|
|
101
|
+
# Local pull/load may run concurrently in your application's executor.
|
|
102
|
+
with RemoteModel("https://your-provider.example", "model-id", token=provider_token) as remote:
|
|
103
|
+
answer = remote.generate("Hello")
|
|
104
|
+
# Switch to your completed local Model for later requests when you choose.
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
This adapter implements the provider's non-streaming `/v1/completions` contract.
|
|
108
|
+
It never reuses Super ii credentials, follows redirects, silently falls back to
|
|
109
|
+
remote execution, or asserts that remote and local model outputs are identical.
|
|
110
|
+
|
|
111
|
+
Sources: [llama.cpp server](https://github.com/ggml-org/llama.cpp/tree/master/tools/server),
|
|
112
|
+
[MLX LM](https://github.com/ml-explore/mlx-lm),
|
|
113
|
+
[vLLM](https://docs.vllm.ai/en/latest/),
|
|
114
|
+
[safetensors](https://huggingface.co/docs/safetensors/),
|
|
115
|
+
[MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk).
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.27,<2"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "superii-sdk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Verified Super ii model acquisition, hardware planning and local inference"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
dependencies = ["httpx>=0.28,<0.29", "filelock>=3.19,<4", "psutil>=7,<8", "cryptography>=46,<51"]
|
|
14
|
+
|
|
15
|
+
[project.optional-dependencies]
|
|
16
|
+
mlx = ["mlx-lm>=0.30,<1; sys_platform == 'darwin'"]
|
|
17
|
+
transformers = ["transformers>=5,<6", "torch>=2.8,<3", "safetensors>=0.6,<1", "accelerate>=1.10,<2"]
|
|
18
|
+
serve = ["fastapi>=0.115,<1", "uvicorn>=0.35,<1", "mcp>=1.20,<2"]
|
|
19
|
+
test = ["pytest>=9,<10", "ruff>=0.16,<1", "fastapi>=0.115,<1", "mcp>=1.20,<2"]
|
|
20
|
+
|
|
21
|
+
[project.scripts]
|
|
22
|
+
superii = "superii.cli:main"
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://superii.site"
|
|
26
|
+
Source = "https://github.com/smavgs/super-ii/tree/main/sdk/python"
|
|
27
|
+
|
|
28
|
+
[tool.hatch.build.targets.wheel]
|
|
29
|
+
packages = ["src/superii"]
|
|
30
|
+
|
|
31
|
+
[tool.pytest.ini_options]
|
|
32
|
+
testpaths = ["tests"]
|
|
33
|
+
|
|
34
|
+
[tool.ruff]
|
|
35
|
+
line-length = 100
|
|
36
|
+
target-version = "py311"
|
|
37
|
+
|
|
38
|
+
[tool.ruff.lint]
|
|
39
|
+
select = ["E", "F", "I", "UP", "B"]
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Super ii: inspect, plan, verify and run immutable local models."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .client import Client, Peer, Snapshot
|
|
6
|
+
from .errors import IntegrityError, PlanError, SuperiiError
|
|
7
|
+
from .hardware import Hardware, hardware
|
|
8
|
+
from .manifest import Manifest
|
|
9
|
+
from .model import Model
|
|
10
|
+
from .planner import Plan
|
|
11
|
+
from .planner import plan as _plan
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
__all__ = [
|
|
15
|
+
"Client",
|
|
16
|
+
"Peer",
|
|
17
|
+
"Snapshot",
|
|
18
|
+
"IntegrityError",
|
|
19
|
+
"PlanError",
|
|
20
|
+
"SuperiiError",
|
|
21
|
+
"Hardware",
|
|
22
|
+
"hardware",
|
|
23
|
+
"Manifest",
|
|
24
|
+
"Model",
|
|
25
|
+
"Plan",
|
|
26
|
+
"inspect",
|
|
27
|
+
"plan",
|
|
28
|
+
"pull",
|
|
29
|
+
"apull",
|
|
30
|
+
"verify",
|
|
31
|
+
"load",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def inspect(repository: str, *, revision: str | None = None, **client_options) -> Manifest:
|
|
36
|
+
with Client(**client_options) as client:
|
|
37
|
+
return client.inspect(repository, revision=revision)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def plan(
|
|
41
|
+
repository: str | Manifest,
|
|
42
|
+
*,
|
|
43
|
+
machine: Hardware | None = None,
|
|
44
|
+
runtime: str | None = None,
|
|
45
|
+
context_size: int = 4096,
|
|
46
|
+
revision: str | None = None,
|
|
47
|
+
**client_options,
|
|
48
|
+
) -> Plan:
|
|
49
|
+
manifest = (
|
|
50
|
+
repository
|
|
51
|
+
if isinstance(repository, Manifest)
|
|
52
|
+
else inspect(repository, revision=revision, **client_options)
|
|
53
|
+
)
|
|
54
|
+
return _plan(manifest, machine or hardware(), runtime=runtime, context_size=context_size)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def pull(repository: str, *, revision: str | None = None, **client_options) -> Snapshot:
|
|
58
|
+
with Client(**client_options) as client:
|
|
59
|
+
return client.pull(repository, revision=revision)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
async def apull(repository: str, *, revision: str | None = None, **client_options) -> Snapshot:
|
|
63
|
+
with Client(**client_options) as client:
|
|
64
|
+
return await client.apull(repository, revision=revision)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def verify(snapshot: Snapshot) -> bool:
|
|
68
|
+
return snapshot.verify()
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def load(
|
|
72
|
+
repository: str,
|
|
73
|
+
*,
|
|
74
|
+
revision: str | None = None,
|
|
75
|
+
runtime: str | None = None,
|
|
76
|
+
context_size: int = 4096,
|
|
77
|
+
lazy_weights: bool = False,
|
|
78
|
+
**client_options,
|
|
79
|
+
) -> Model:
|
|
80
|
+
with Client(**client_options) as client:
|
|
81
|
+
manifest = client.inspect(repository, revision=revision)
|
|
82
|
+
selected = _plan(manifest, hardware(), runtime=runtime, context_size=context_size)
|
|
83
|
+
snapshot = client.pull(repository, revision=selected.revision, files=selected.files)
|
|
84
|
+
return Model(snapshot, selected, lazy_weights=lazy_weights)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import json
|
|
5
|
+
from collections.abc import Mapping
|
|
6
|
+
|
|
7
|
+
from cryptography.exceptions import InvalidSignature
|
|
8
|
+
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
|
|
9
|
+
|
|
10
|
+
from .errors import IntegrityError
|
|
11
|
+
from .manifest import Manifest
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def verify_attestation(manifest: Manifest, trusted_keys: Mapping[str, str]) -> bool:
|
|
15
|
+
proof = manifest.publication
|
|
16
|
+
if not proof:
|
|
17
|
+
raise IntegrityError("This release has no automatic publication attestation")
|
|
18
|
+
try:
|
|
19
|
+
key = trusted_keys[proof["key_id"]]
|
|
20
|
+
payload = proof["payload"]
|
|
21
|
+
Ed25519PublicKey.from_public_bytes(base64.b64decode(key, validate=True)).verify(
|
|
22
|
+
base64.b64decode(proof["signature"], validate=True),
|
|
23
|
+
payload.encode(),
|
|
24
|
+
)
|
|
25
|
+
data = json.loads(payload)
|
|
26
|
+
if (
|
|
27
|
+
data["manifest_sha256"] != manifest.manifest_sha256
|
|
28
|
+
or data["repository_id"] != manifest.repository_id
|
|
29
|
+
or data["revision_id"] != manifest.revision_id
|
|
30
|
+
or data["commit_sha"] != manifest.revision
|
|
31
|
+
or data["outcome"] != "passed"
|
|
32
|
+
or data["policy_version"] != "superii-auto-publish-v1"
|
|
33
|
+
):
|
|
34
|
+
raise IntegrityError("Publication attestation does not approve this manifest")
|
|
35
|
+
except (KeyError, TypeError, ValueError, InvalidSignature) as error:
|
|
36
|
+
raise IntegrityError(
|
|
37
|
+
"Publication signature is missing, invalid or signed by an untrusted key"
|
|
38
|
+
) from error
|
|
39
|
+
return True
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
from dataclasses import asdict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
from . import Client, hardware, load, plan
|
|
10
|
+
from .experiments import benchmark
|
|
11
|
+
|
|
12
|
+
parser = argparse.ArgumentParser(prog="superii")
|
|
13
|
+
parser.add_argument("--base-url", default="https://superii.site")
|
|
14
|
+
parser.add_argument("--cache-dir")
|
|
15
|
+
commands = parser.add_subparsers(dest="command", required=True)
|
|
16
|
+
commands.add_parser("hardware")
|
|
17
|
+
for name in ("inspect", "plan", "pull", "generate", "benchmark", "mcp", "serve"):
|
|
18
|
+
sub = commands.add_parser(name)
|
|
19
|
+
sub.add_argument("repository")
|
|
20
|
+
sub.add_argument("--revision")
|
|
21
|
+
if name in {"plan", "generate", "benchmark", "mcp", "serve"}:
|
|
22
|
+
sub.add_argument("--runtime", choices=["llama.cpp", "mlx", "transformers", "vllm"])
|
|
23
|
+
sub.add_argument("--context-size", type=int, default=4096)
|
|
24
|
+
if name in {"generate", "benchmark"}:
|
|
25
|
+
sub.add_argument("prompt")
|
|
26
|
+
sub.add_argument("--max-tokens", type=int, default=128)
|
|
27
|
+
if name == "serve":
|
|
28
|
+
sub.add_argument("--port", type=int, default=8765)
|
|
29
|
+
args = parser.parse_args()
|
|
30
|
+
if args.command == "hardware":
|
|
31
|
+
print(json.dumps(asdict(hardware()), indent=2))
|
|
32
|
+
return
|
|
33
|
+
options = {"base_url": args.base_url, "cache_dir": args.cache_dir}
|
|
34
|
+
if args.command in {"inspect", "pull"}:
|
|
35
|
+
with Client(**options) as client:
|
|
36
|
+
result = getattr(client, args.command)(args.repository, revision=args.revision)
|
|
37
|
+
print(json.dumps(asdict(result), indent=2, default=str))
|
|
38
|
+
elif args.command == "plan":
|
|
39
|
+
print(
|
|
40
|
+
json.dumps(
|
|
41
|
+
asdict(
|
|
42
|
+
plan(
|
|
43
|
+
args.repository,
|
|
44
|
+
revision=args.revision,
|
|
45
|
+
runtime=args.runtime,
|
|
46
|
+
context_size=args.context_size,
|
|
47
|
+
**options,
|
|
48
|
+
)
|
|
49
|
+
),
|
|
50
|
+
indent=2,
|
|
51
|
+
)
|
|
52
|
+
)
|
|
53
|
+
else:
|
|
54
|
+
with load(
|
|
55
|
+
args.repository,
|
|
56
|
+
revision=args.revision,
|
|
57
|
+
runtime=args.runtime,
|
|
58
|
+
context_size=args.context_size,
|
|
59
|
+
**options,
|
|
60
|
+
) as model:
|
|
61
|
+
if args.command == "mcp":
|
|
62
|
+
model.serve_mcp()
|
|
63
|
+
elif args.command == "serve":
|
|
64
|
+
import os
|
|
65
|
+
|
|
66
|
+
token = os.environ.get("SUPERII_SERVING_TOKEN", "")
|
|
67
|
+
if len(token) < 32:
|
|
68
|
+
parser.error(
|
|
69
|
+
"Set SUPERII_SERVING_TOKEN to a random local token (32+ characters)"
|
|
70
|
+
)
|
|
71
|
+
model.serve(port=args.port, token=token)
|
|
72
|
+
elif args.command == "benchmark":
|
|
73
|
+
print(
|
|
74
|
+
json.dumps(benchmark(model, args.prompt, max_tokens=args.max_tokens), indent=2)
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
print(model.generate(args.prompt, max_tokens=args.max_tokens))
|