programasweights 0.4.7__tar.gz → 0.4.8__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.
- {programasweights-0.4.7 → programasweights-0.4.8}/CHANGELOG.md +5 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/PKG-INFO +1 -1
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/__init__.py +1 -1
- {programasweights-0.4.7 → programasweights-0.4.8}/pyproject.toml +11 -1
- programasweights-0.4.7/.cursor/rules/releases.mdc +0 -17
- programasweights-0.4.7/.github/workflows/release.yml +0 -72
- programasweights-0.4.7/.github/workflows/test.yml +0 -94
- programasweights-0.4.7/.readthedocs.yaml +0 -13
- programasweights-0.4.7/AGENTS.md +0 -291
- programasweights-0.4.7/RELEASING.md +0 -82
- programasweights-0.4.7/docs/adr/001-llama-cpp-over-pytorch.md +0 -21
- programasweights-0.4.7/docs/adr/002-q4_0-adapter-format.md +0 -32
- programasweights-0.4.7/docs/adr/003-single-spec-field.md +0 -26
- programasweights-0.4.7/docs/adr/004-compiler-naming.md +0 -32
- programasweights-0.4.7/docs/adr/005-vllm-hidden-states.md +0 -24
- programasweights-0.4.7/docs/adr/006-email-api-key-auth.md +0 -41
- programasweights-0.4.7/docs/advanced/adrs.md +0 -67
- programasweights-0.4.7/docs/advanced/architecture.md +0 -47
- programasweights-0.4.7/docs/api-reference/cli.md +0 -110
- programasweights-0.4.7/docs/api-reference/python-sdk.md +0 -363
- programasweights-0.4.7/docs/api-reference/rest-api.md +0 -200
- programasweights-0.4.7/docs/architecture.md +0 -38
- programasweights-0.4.7/docs/case-studies/alien-taboo.md +0 -117
- programasweights-0.4.7/docs/case-studies/log-monitoring.md +0 -132
- programasweights-0.4.7/docs/case-studies/semantic-search.md +0 -146
- programasweights-0.4.7/docs/case-studies/site-navigation.md +0 -127
- programasweights-0.4.7/docs/case-studies/tool-calling.md +0 -477
- programasweights-0.4.7/docs/getting-started/first-program.md +0 -88
- programasweights-0.4.7/docs/getting-started/installation.md +0 -57
- programasweights-0.4.7/docs/getting-started/naming-programs.md +0 -78
- programasweights-0.4.7/docs/guide/browser-inference.md +0 -141
- programasweights-0.4.7/docs/guide/how-it-works.md +0 -47
- programasweights-0.4.7/docs/guide/local-inference.md +0 -48
- programasweights-0.4.7/docs/guide/writing-good-specs.md +0 -11
- programasweights-0.4.7/docs/hub/browsing-programs.md +0 -37
- programasweights-0.4.7/docs/hub/feedback-cases.md +0 -34
- programasweights-0.4.7/docs/hub/publishing-programs.md +0 -31
- programasweights-0.4.7/docs/index.md +0 -96
- programasweights-0.4.7/docs/requirements.txt +0 -2
- programasweights-0.4.7/examples/flask_app.py +0 -52
- programasweights-0.4.7/examples/jupyter_notebook.py +0 -52
- programasweights-0.4.7/examples/langchain_integration.py +0 -52
- programasweights-0.4.7/examples/paw_monitor.py +0 -180
- programasweights-0.4.7/examples/replace_openai.py +0 -44
- programasweights-0.4.7/mkdocs.yml +0 -87
- programasweights-0.4.7/scripts/release_metadata.py +0 -156
- programasweights-0.4.7/tests/test_api_errors.py +0 -222
- programasweights-0.4.7/tests/test_base_interpreter.py +0 -845
- programasweights-0.4.7/tests/test_cli_auth.py +0 -265
- programasweights-0.4.7/tests/test_compile_timeouts.py +0 -129
- programasweights-0.4.7/tests/test_desktop_sdk.py +0 -1221
- programasweights-0.4.7/tests/test_local_program.py +0 -676
- programasweights-0.4.7/tests/test_offline_cache.py +0 -97
- programasweights-0.4.7/tests/test_release_metadata.py +0 -296
- programasweights-0.4.7/tests/test_remote_inference.py +0 -294
- programasweights-0.4.7/tests/test_runtime_registry_sdk.py +0 -123
- programasweights-0.4.7/tests/test_sdk.py +0 -484
- programasweights-0.4.7/tests/test_sdk.sh +0 -89
- {programasweights-0.4.7 → programasweights-0.4.8}/.gitignore +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/LICENSE +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/PYPI_README.md +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/README.md +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/_output.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/_program_reference.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/_remote.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/artifacts.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/cache.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/cli.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/client.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/compiler/__init__.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/compiler/dummy.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/config.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/convert_peft_to_paw.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/errors.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/local_program.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/paw_format.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/runtime/__init__.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/runtime/interpreter.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/runtime/interpreter_onnx.py +0 -0
- {programasweights-0.4.7 → programasweights-0.4.8}/programasweights/runtime_llamacpp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: programasweights
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.8
|
|
4
4
|
Summary: Compile natural language specifications into neural programs that run locally via llama.cpp.
|
|
5
5
|
Project-URL: Homepage, https://programasweights.com
|
|
6
6
|
Project-URL: Repository, https://github.com/programasweights/programasweights-python
|
|
@@ -27,7 +27,7 @@ try:
|
|
|
27
27
|
from importlib.metadata import version as _meta_version
|
|
28
28
|
__version__ = _meta_version("programasweights")
|
|
29
29
|
except Exception:
|
|
30
|
-
__version__ = "0.4.
|
|
30
|
+
__version__ = "0.4.8"
|
|
31
31
|
|
|
32
32
|
from ._output import ProgressCallback, ProgressEvent, report_progress
|
|
33
33
|
from .cache import CachedProgram
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "programasweights"
|
|
7
|
-
version = "0.4.
|
|
7
|
+
version = "0.4.8"
|
|
8
8
|
description = "Compile natural language specifications into neural programs that run locally via llama.cpp."
|
|
9
9
|
readme = "PYPI_README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -47,6 +47,16 @@ paw = "programasweights.cli:main"
|
|
|
47
47
|
[tool.hatch.build.targets.wheel]
|
|
48
48
|
packages = ["programasweights"]
|
|
49
49
|
|
|
50
|
+
[tool.hatch.build.targets.sdist]
|
|
51
|
+
only-include = [
|
|
52
|
+
"programasweights",
|
|
53
|
+
"README.md",
|
|
54
|
+
"PYPI_README.md",
|
|
55
|
+
"LICENSE",
|
|
56
|
+
"CHANGELOG.md",
|
|
57
|
+
"pyproject.toml",
|
|
58
|
+
]
|
|
59
|
+
|
|
50
60
|
[tool.pytest.ini_options]
|
|
51
61
|
addopts = "-q"
|
|
52
62
|
pythonpath = ["."]
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: Publish and verify complete Python SDK releases
|
|
3
|
-
alwaysApply: true
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# SDK releases
|
|
7
|
-
|
|
8
|
-
For release or publication work, read `RELEASING.md` first.
|
|
9
|
-
|
|
10
|
-
- A release is complete only when its annotated remote tag, PyPI wheel and
|
|
11
|
-
source distribution, and published GitHub Release all exist and agree.
|
|
12
|
-
- Build from the clean, tested release commit; push its annotated version tag
|
|
13
|
-
before uploading the exact checked artifacts to PyPI.
|
|
14
|
-
- Verify the `GitHub release` workflow succeeded and the latest GitHub Release
|
|
15
|
-
agrees with PyPI. A tag alone is not a GitHub Release entry.
|
|
16
|
-
- Repair missing entries using the documented workflow dispatch. Never move a
|
|
17
|
-
published tag, rebuild an existing version, or bypass artifact verification.
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
name: GitHub release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags: ['v*']
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
inputs:
|
|
8
|
-
tag:
|
|
9
|
-
description: 'Existing stable version tag, e.g. v0.4.6'
|
|
10
|
-
required: true
|
|
11
|
-
type: string
|
|
12
|
-
|
|
13
|
-
permissions:
|
|
14
|
-
contents: write
|
|
15
|
-
|
|
16
|
-
concurrency:
|
|
17
|
-
group: github-release-${{ inputs.tag || github.ref_name }}
|
|
18
|
-
cancel-in-progress: false
|
|
19
|
-
|
|
20
|
-
jobs:
|
|
21
|
-
release:
|
|
22
|
-
runs-on: ubuntu-latest
|
|
23
|
-
timeout-minutes: 15
|
|
24
|
-
env:
|
|
25
|
-
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
|
|
26
|
-
GH_TOKEN: ${{ github.token }}
|
|
27
|
-
GH_REPO: ${{ github.repository }}
|
|
28
|
-
steps:
|
|
29
|
-
- name: Set the verification output directory
|
|
30
|
-
run: echo "RELEASE_DIR=$RUNNER_TEMP/verified-release" >> "$GITHUB_ENV"
|
|
31
|
-
- uses: actions/checkout@v4
|
|
32
|
-
with:
|
|
33
|
-
fetch-depth: 0
|
|
34
|
-
- uses: actions/setup-python@v5
|
|
35
|
-
with:
|
|
36
|
-
python-version: '3.12'
|
|
37
|
-
- name: Verify the remote tag and both published PyPI artifacts
|
|
38
|
-
# Tags are pushed before uploading. Wait for the wheel AND sdist;
|
|
39
|
-
# never announce an unpublished version or rebuild release assets.
|
|
40
|
-
run: python scripts/release_metadata.py --tag "$RELEASE_TAG" --output-dir "$RELEASE_DIR" --wait-seconds 600
|
|
41
|
-
- name: Publish the missing GitHub release
|
|
42
|
-
shell: bash
|
|
43
|
-
run: |
|
|
44
|
-
set -euo pipefail
|
|
45
|
-
if gh release view "$RELEASE_TAG" --json tagName >/dev/null 2>&1; then
|
|
46
|
-
echo "Release already exists; preserving its notes and assets."
|
|
47
|
-
else
|
|
48
|
-
latest=$(jq -r .latest "$RELEASE_DIR/verified.json")
|
|
49
|
-
gh release create "$RELEASE_TAG" "$RELEASE_DIR"/artifacts/* \
|
|
50
|
-
--verify-tag --title "$RELEASE_TAG" \
|
|
51
|
-
--notes-file "$RELEASE_DIR/notes.md" --latest="$latest"
|
|
52
|
-
fi
|
|
53
|
-
gh release view "$RELEASE_TAG" --json tagName,isDraft,isPrerelease,url \
|
|
54
|
-
| jq -e --arg tag "$RELEASE_TAG" '.tagName == $tag and .isDraft == false and .isPrerelease == false'
|
|
55
|
-
- name: Verify the uploaded release assets and latest marker
|
|
56
|
-
shell: bash
|
|
57
|
-
run: |
|
|
58
|
-
set -euo pipefail
|
|
59
|
-
gh release download "$RELEASE_TAG" --pattern 'programasweights-*' \
|
|
60
|
-
--dir "$RELEASE_DIR/github-assets"
|
|
61
|
-
for artifact in "$RELEASE_DIR"/artifacts/*; do
|
|
62
|
-
cmp "$artifact" "$RELEASE_DIR/github-assets/$(basename "$artifact")"
|
|
63
|
-
done
|
|
64
|
-
if [ "$(jq -r .latest "$RELEASE_DIR/verified.json")" = true ]; then
|
|
65
|
-
gh api "repos/$GH_REPO/releases/latest" \
|
|
66
|
-
| jq -e --arg tag "$RELEASE_TAG" '.tag_name == $tag'
|
|
67
|
-
fi
|
|
68
|
-
- name: Retain the verification record
|
|
69
|
-
uses: actions/upload-artifact@v4
|
|
70
|
-
with:
|
|
71
|
-
name: release-verification-${{ inputs.tag || github.ref_name }}
|
|
72
|
-
path: ${{ runner.temp }}/verified-release/verified.json
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
name: tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [main]
|
|
6
|
-
pull_request:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
release-metadata:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
steps:
|
|
12
|
-
- uses: actions/checkout@v4
|
|
13
|
-
- uses: actions/setup-python@v5
|
|
14
|
-
with:
|
|
15
|
-
python-version: '3.12'
|
|
16
|
-
- run: python -m pip install pytest
|
|
17
|
-
- name: Test release verification without network or publishing
|
|
18
|
-
run: python -m pytest tests/test_release_metadata.py
|
|
19
|
-
|
|
20
|
-
test:
|
|
21
|
-
runs-on: ubuntu-latest
|
|
22
|
-
strategy:
|
|
23
|
-
fail-fast: false
|
|
24
|
-
matrix:
|
|
25
|
-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
26
|
-
steps:
|
|
27
|
-
- uses: actions/checkout@v4
|
|
28
|
-
|
|
29
|
-
- name: Set up Python ${{ matrix.python-version }}
|
|
30
|
-
uses: actions/setup-python@v5
|
|
31
|
-
with:
|
|
32
|
-
python-version: ${{ matrix.python-version }}
|
|
33
|
-
|
|
34
|
-
- name: Install (hermetic deps only)
|
|
35
|
-
# Install httpx + pytest and the package itself without pulling the heavy
|
|
36
|
-
# llama-cpp-python build. Runtime tests inject a fake llama_cpp module,
|
|
37
|
-
# so CI needs neither the native extension nor a model download.
|
|
38
|
-
run: |
|
|
39
|
-
python -m pip install --upgrade pip
|
|
40
|
-
python -m pip install httpx pytest
|
|
41
|
-
python -m pip install -e . --no-deps
|
|
42
|
-
|
|
43
|
-
- name: Run hermetic tests
|
|
44
|
-
# Scoped to tests that need no network, no model download, and no
|
|
45
|
-
# PAW_API_KEY. Auth tests (@needs_auth) auto-skip without a key; the
|
|
46
|
-
# network/model-download tests in test_sdk.py are excluded here and can
|
|
47
|
-
# be run separately against a live server.
|
|
48
|
-
run: |
|
|
49
|
-
pytest \
|
|
50
|
-
tests/test_api_errors.py \
|
|
51
|
-
tests/test_compile_timeouts.py \
|
|
52
|
-
tests/test_local_program.py \
|
|
53
|
-
tests/test_base_interpreter.py \
|
|
54
|
-
tests/test_cli_auth.py \
|
|
55
|
-
tests/test_remote_inference.py \
|
|
56
|
-
tests/test_desktop_sdk.py \
|
|
57
|
-
tests/test_runtime_registry_sdk.py \
|
|
58
|
-
tests/test_sdk.py::TestInstallAndImport
|
|
59
|
-
|
|
60
|
-
local-files-windows:
|
|
61
|
-
runs-on: windows-latest
|
|
62
|
-
strategy:
|
|
63
|
-
fail-fast: false
|
|
64
|
-
matrix:
|
|
65
|
-
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
|
|
66
|
-
steps:
|
|
67
|
-
- uses: actions/checkout@v4
|
|
68
|
-
- uses: actions/setup-python@v5
|
|
69
|
-
with:
|
|
70
|
-
python-version: ${{ matrix.python-version }}
|
|
71
|
-
- name: Install hermetic test dependencies
|
|
72
|
-
run: |
|
|
73
|
-
python -m pip install httpx pytest
|
|
74
|
-
python -m pip install -e . --no-deps
|
|
75
|
-
- name: Test Windows local paths, cache locks, and compile errors
|
|
76
|
-
run: python -m pytest tests/test_api_errors.py tests/test_compile_timeouts.py tests/test_local_program.py tests/test_remote_inference.py --junitxml=test-results.xml
|
|
77
|
-
- name: Annotate Windows test failures
|
|
78
|
-
if: failure()
|
|
79
|
-
shell: python
|
|
80
|
-
run: |
|
|
81
|
-
from pathlib import Path
|
|
82
|
-
import xml.etree.ElementTree as ET
|
|
83
|
-
|
|
84
|
-
report = Path("test-results.xml")
|
|
85
|
-
if report.exists():
|
|
86
|
-
for case in ET.parse(report).iter("testcase"):
|
|
87
|
-
for result in case:
|
|
88
|
-
if result.tag in {"failure", "error"}:
|
|
89
|
-
# GitHub truncates annotations, so retain the actual
|
|
90
|
-
# exception at the end of long pytest tracebacks.
|
|
91
|
-
detail = result.text or result.get("message", "")
|
|
92
|
-
message = f"{case.get('name')}: {detail[-3500:]}"
|
|
93
|
-
message = message.replace("%", "%25").replace("\r", "%0D").replace("\n", "%0A")
|
|
94
|
-
print(f"::error::{message}")
|
programasweights-0.4.7/AGENTS.md
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
# ProgramAsWeights (PAW)
|
|
2
|
-
|
|
3
|
-
PAW compiles natural language specifications into tiny neural functions that run locally. Each function takes a single text input and returns a single text output. Use it when you need fuzzy text processing — classification, extraction, format repair, search, triage — that regex can't handle but a full LLM is overkill for.
|
|
4
|
-
|
|
5
|
-
Website: https://programasweights.com
|
|
6
|
-
Full documentation: https://programasweights.readthedocs.io
|
|
7
|
-
|
|
8
|
-
## When to Use PAW
|
|
9
|
-
|
|
10
|
-
- **Fuzzy search** — typo-tolerant matching, semantic search, near-duplicate detection
|
|
11
|
-
- **Format repair** — fix broken JSON, normalize dates, repair malformed inputs
|
|
12
|
-
- **Classification** — sentiment, urgency, categories defined in your own words
|
|
13
|
-
- **Extraction** — emails, names, dates from messy unstructured text
|
|
14
|
-
- **Log triage** — extract errors from verbose output, filter noise
|
|
15
|
-
- **Intent routing** — map user descriptions to the closest URL, menu item, or setting
|
|
16
|
-
- **Agent preprocessing** — parse tool calls, validate outputs, route tasks
|
|
17
|
-
|
|
18
|
-
## Install
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
pip install programasweights --extra-index-url https://pypi.programasweights.com/simple/
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Quickstart
|
|
25
|
-
|
|
26
|
-
```python
|
|
27
|
-
import programasweights as paw
|
|
28
|
-
|
|
29
|
-
# Use a pre-compiled function (downloads once, runs locally forever)
|
|
30
|
-
fn = paw.function("email-triage")
|
|
31
|
-
fn("Urgent: server is down!") # "immediate"
|
|
32
|
-
fn("Newsletter: spring picnic") # "wait"
|
|
33
|
-
|
|
34
|
-
# Compile your own from a description
|
|
35
|
-
program = paw.compile(
|
|
36
|
-
"Fix malformed JSON: repair missing quotes and trailing commas"
|
|
37
|
-
)
|
|
38
|
-
fn = paw.function(program.id)
|
|
39
|
-
fn("{name: 'Alice',}") # '{"name":"Alice"}'
|
|
40
|
-
|
|
41
|
-
# Or compile and load in one step
|
|
42
|
-
fn = paw.compile_and_load("Classify sentiment as positive or negative")
|
|
43
|
-
fn("I love this!") # "positive"
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Load a local `.paw` file with `paw.function("./classifier.paw")` (SDK 0.4.5+).
|
|
47
|
-
|
|
48
|
-
If you want the smaller browser-compatible runtime explicitly, pass `compiler="paw-4b-gpt2"`. Otherwise, omit `compiler` and let the server default decide.
|
|
49
|
-
|
|
50
|
-
## Remote inference (optional)
|
|
51
|
-
|
|
52
|
-
Use the hosted API for fast inference in around 150 ms, without a local model download.
|
|
53
|
-
|
|
54
|
-
### Python SDK
|
|
55
|
-
|
|
56
|
-
```python
|
|
57
|
-
import programasweights as paw
|
|
58
|
-
|
|
59
|
-
with paw.function("email-triage", remote=True) as remote_fn:
|
|
60
|
-
print(remote_fn("Urgent: the server is down!"))
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
For authenticated requests, set `PAW_API_KEY` or use `paw.login()`.
|
|
64
|
-
|
|
65
|
-
### Direct HTTP
|
|
66
|
-
|
|
67
|
-
Use `httpx` directly without installing the PAW SDK.
|
|
68
|
-
|
|
69
|
-
```python
|
|
70
|
-
import httpx
|
|
71
|
-
|
|
72
|
-
with httpx.Client(timeout=60.0) as client:
|
|
73
|
-
response = client.post(
|
|
74
|
-
"https://programasweights.com/api/v1/infer",
|
|
75
|
-
json={
|
|
76
|
-
"program_id": "email-triage",
|
|
77
|
-
"input": "Urgent: server is down!"
|
|
78
|
-
},
|
|
79
|
-
)
|
|
80
|
-
response.raise_for_status()
|
|
81
|
-
print(response.json()["output"])
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
For authenticated requests, pass `headers={"X-API-Key": api_key}` to `client.post()`.
|
|
85
|
-
|
|
86
|
-
## Current Public Compilers
|
|
87
|
-
|
|
88
|
-
- **Standard** (`paw-4b-qwen3-0.6b`) — higher accuracy, 594 MB base + ~22 MB/program. This is the current server default.
|
|
89
|
-
- **Compact** (`paw-4b-gpt2`) — smaller (134 MB base + ~5 MB/program), runs in browser via WebAssembly.
|
|
90
|
-
|
|
91
|
-
Best practice:
|
|
92
|
-
|
|
93
|
-
- For quickstarts and reusable agent workflows, prefer `paw.compile(spec)` with no explicit compiler.
|
|
94
|
-
- If you need to target a specific runtime, pass `compiler="paw-4b-gpt2"` or another supported alias explicitly.
|
|
95
|
-
- If you need to inspect current server-supported compiler names at runtime, call `paw.list_compilers()`.
|
|
96
|
-
|
|
97
|
-
## Writing Good Specs
|
|
98
|
-
|
|
99
|
-
**The #1 practice: iterate with test cases.** Do not accept low performance on the first try. Build a test suite of input/output pairs, measure accuracy, then iteratively adjust wording and formatting until performance is good enough. Treat spec writing like software engineering: test, debug specific failures, fix the wording, retest.
|
|
100
|
-
|
|
101
|
-
A good spec has a description plus `Input: ... Output: ...` examples.
|
|
102
|
-
|
|
103
|
-
```python
|
|
104
|
-
fn = paw.compile_and_load("""
|
|
105
|
-
Classify user intent. Return ONLY one of: search, create, delete, other.
|
|
106
|
-
|
|
107
|
-
Input: Find the latest report
|
|
108
|
-
Output: search
|
|
109
|
-
|
|
110
|
-
Input: Make a new folder
|
|
111
|
-
Output: create
|
|
112
|
-
|
|
113
|
-
Input: Remove old backups
|
|
114
|
-
Output: delete
|
|
115
|
-
""")
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
**Spec-tuning tips:**
|
|
119
|
-
|
|
120
|
-
- **State output constraints explicitly**: "Return ONLY one of: X, Y, Z". Without this the model may produce free-form text.
|
|
121
|
-
- **Include examples from your actual data**: Examples outperform prose-only descriptions.
|
|
122
|
-
- **Debug failures before sweeping**: Look at specific failing examples and understand WHY before trying many variants.
|
|
123
|
-
|
|
124
|
-
## Constraints And Runtime Behavior
|
|
125
|
-
|
|
126
|
-
- Each PAW function is stateless: one text input, one text output. No conversation history.
|
|
127
|
-
- Spec + input + output share a ~2048 token context window. Inputs that exceed it will error.
|
|
128
|
-
- `max_tokens` defaults to `None`: generation runs until EOS or the context limit.
|
|
129
|
-
- Compile runs on the hosted PAW API. Inference should usually run locally through the SDK.
|
|
130
|
-
- Synchronous compile requests use a 40-minute read timeout.
|
|
131
|
-
- **Run local inference sequentially by default.** With PAW’s current llama.cpp backend, simultaneous inference calls often perform worse. Reuse loaded functions and process inputs one at a time; never call the same function instance concurrently.
|
|
132
|
-
- **GPU acceleration** is enabled by default (`n_gpu_layers=-1`). Uses Metal on Mac, CUDA on Linux, and falls back to CPU automatically. If GPU causes issues, set `PAW_GPU_LAYERS=0` or pass `n_gpu_layers=0`.
|
|
133
|
-
- **First call** is usually ~1-5s because it loads the base model. Subsequent calls are typically ~0.05-0.5s depending on input length and GPU availability.
|
|
134
|
-
- **Base model files are shared** across programs on disk. Each Standard LoRA adapter is ~22 MB; each Compact LoRA adapter is ~5 MB.
|
|
135
|
-
- Cache root is `~/.cache/programasweights/`. Override with `PAW_CACHE_DIR`.
|
|
136
|
-
- After the first download, inference works offline. Pass `offline=True` or set
|
|
137
|
-
`PAW_OFFLINE=1` to prohibit network access and fail if any validated asset is
|
|
138
|
-
missing.
|
|
139
|
-
- Advanced only: `paw.function(None, interpreter="gpt2")` runs a supported
|
|
140
|
-
base model without a compiled adapter; consult the Python API reference for
|
|
141
|
-
its strict prompt and offline semantics.
|
|
142
|
-
|
|
143
|
-
## Common Errors
|
|
144
|
-
|
|
145
|
-
Compile API HTTP errors raise `paw.APIError`. Check `error.code` and `error.message` for details. The SDK does not retry automatically.
|
|
146
|
-
|
|
147
|
-
| Error | Cause | Fix |
|
|
148
|
-
|-------|-------|-----|
|
|
149
|
-
| `RuntimeError: assets not ready` on download | Program is still generating after compile | The SDK polls automatically for up to 60s. If it still fails, retry shortly or recompile. |
|
|
150
|
-
| `httpx.HTTPStatusError: 422` on compile | Spec too short (<10 chars) or request validation failed | Adjust spec length or request shape. |
|
|
151
|
-
| `httpx.HTTPStatusError: 429` | Hosted compile API limit exceeded | Wait, or sign in for higher compile limits. |
|
|
152
|
-
| GPU/Metal errors on load | GPU backend not available or incompatible | Set `PAW_GPU_LAYERS=0` or pass `n_gpu_layers=0` to force CPU. |
|
|
153
|
-
|
|
154
|
-
## Browser / JavaScript SDK
|
|
155
|
-
|
|
156
|
-
Programs compiled with `paw-4b-gpt2` run in the browser via WebAssembly.
|
|
157
|
-
|
|
158
|
-
```bash
|
|
159
|
-
npm install @programasweights/web
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
```javascript
|
|
163
|
-
import paw from '@programasweights/web';
|
|
164
|
-
|
|
165
|
-
const fn = await paw.function('email-triage-browser');
|
|
166
|
-
const result = await fn('Urgent: server is down!');
|
|
167
|
-
// result: "immediate"
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
The browser SDK resolves slugs through the PAW API, then downloads browser assets from Hugging Face and runs inference client-side. If you load by program ID, browser inference stays independent of the PAW API at runtime.
|
|
171
|
-
|
|
172
|
-
## Authentication (optional)
|
|
173
|
-
|
|
174
|
-
Sign in for higher rate limits and program naming. Everything works without it.
|
|
175
|
-
|
|
176
|
-
```bash
|
|
177
|
-
export PAW_API_KEY=paw_sk_...
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
Generate API keys at https://programasweights.com/settings.
|
|
181
|
-
|
|
182
|
-
| | Anonymous | Authenticated |
|
|
183
|
-
|---|---|---|
|
|
184
|
-
| Compile rate limit | 20/hr | 60/hr |
|
|
185
|
-
| Concurrent compile requests | 1 | 2 |
|
|
186
|
-
| Name programs (slugs) | No | Yes |
|
|
187
|
-
|
|
188
|
-
Hosted API limits apply to compile requests. Most inference should run locally through the SDK.
|
|
189
|
-
|
|
190
|
-
## CLI
|
|
191
|
-
|
|
192
|
-
Commands: `paw compile --spec "..." --json`, `paw run --program <id> --input "..." [--offline]`, `paw info <id>`, `paw rename <id> <slug>`, `paw login`. All support `--json` for structured output.
|
|
193
|
-
|
|
194
|
-
## Versioning
|
|
195
|
-
|
|
196
|
-
Slugs support version history. Recompiling with the same slug creates a new version:
|
|
197
|
-
|
|
198
|
-
```python
|
|
199
|
-
p1 = paw.compile("Count words v1", slug="word-counter") # v1
|
|
200
|
-
p2 = paw.compile("Count words v2", slug="word-counter") # v2 (auto-bumps)
|
|
201
|
-
|
|
202
|
-
fn = paw.function("da03/word-counter") # resolves to main (latest)
|
|
203
|
-
fn = paw.function("da03/word-counter@v1") # pinned to v1
|
|
204
|
-
|
|
205
|
-
versions = paw.list_versions("da03/word-counter") # all versions
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
Pinned versions (`@v1`) are immutable and cached locally forever. Bare slugs always check the server for the latest main version and fall back to cache if offline.
|
|
209
|
-
|
|
210
|
-
## Full API Reference
|
|
211
|
-
|
|
212
|
-
```python
|
|
213
|
-
program = paw.compile(
|
|
214
|
-
spec, # natural language specification (10-16000 chars)
|
|
215
|
-
compiler=None, # omit to use the current server default (today: paw-4b-qwen3-0.6b)
|
|
216
|
-
slug=None, # URL-safe handle (requires auth)
|
|
217
|
-
public=True, # list on public hub
|
|
218
|
-
)
|
|
219
|
-
# Returns: Program(id, slug, status, version, version_action, timings, error)
|
|
220
|
-
|
|
221
|
-
fn = paw.function(program) # accepts Program object, hash ID, or slug
|
|
222
|
-
fn = paw.function("a6b454023d41ac9ca845")
|
|
223
|
-
fn = paw.function("da03/my-classifier")
|
|
224
|
-
fn = paw.function("da03/my-classifier@v2") # pinned version
|
|
225
|
-
fn = paw.function("da03/my-classifier", offline=True) # skip server check
|
|
226
|
-
|
|
227
|
-
result: str = fn(input_text: str, max_tokens=None, temperature=0.0)
|
|
228
|
-
|
|
229
|
-
prepared = paw.prepare_program("da03/my-classifier")
|
|
230
|
-
ready = paw.is_offline_ready("da03/my-classifier") # zero network
|
|
231
|
-
cached = paw.list_cached_programs()
|
|
232
|
-
|
|
233
|
-
fn = paw.compile_and_load(spec)
|
|
234
|
-
|
|
235
|
-
job = paw.compile_async(spec, compiler="paw-ft-bs48") # explicit finetune compiler required
|
|
236
|
-
status = paw.get_compile_status(job["job_id"])
|
|
237
|
-
|
|
238
|
-
versions = paw.list_versions("da03/my-classifier") # version history
|
|
239
|
-
programs = paw.list_programs(sort="recent", per_page=20) # requires auth
|
|
240
|
-
compilers = paw.list_compilers() # discover available compilers at runtime
|
|
241
|
-
|
|
242
|
-
paw.login()
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
## Chaining Functions
|
|
246
|
-
|
|
247
|
-
Multiple PAW functions can be composed for multi-step tasks:
|
|
248
|
-
|
|
249
|
-
```python
|
|
250
|
-
classifier = paw.compile_and_load("Classify the bug type. Return ONLY one of: off-by-one, type-error, other")
|
|
251
|
-
fixer = paw.compile_and_load("Fix the bug described in the first line. Return only the corrected code.")
|
|
252
|
-
|
|
253
|
-
label = classifier(code_snippet)
|
|
254
|
-
if label != "other":
|
|
255
|
-
fix = fixer(f"{label}: {code_snippet}")
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
Chain them with regular Python logic.
|
|
259
|
-
|
|
260
|
-
## Worked Example: Log Monitoring
|
|
261
|
-
|
|
262
|
-
PAW functions can classify log output. Compile once with examples from your specific logs, then reuse the function locally forever:
|
|
263
|
-
|
|
264
|
-
```python
|
|
265
|
-
program = paw.compile("""
|
|
266
|
-
Classify log lines. Return ONLY one word: ALERT or QUIET.
|
|
267
|
-
|
|
268
|
-
Input: [step 100] loss=0.05 lr=0.0001
|
|
269
|
-
Output: QUIET
|
|
270
|
-
|
|
271
|
-
Input: [Checkpoint] Saved model at step 1000
|
|
272
|
-
Output: ALERT
|
|
273
|
-
|
|
274
|
-
Input: Traceback (most recent call last):
|
|
275
|
-
Output: ALERT
|
|
276
|
-
|
|
277
|
-
Input: Training complete. Final loss: 0.11
|
|
278
|
-
Output: ALERT
|
|
279
|
-
""")
|
|
280
|
-
|
|
281
|
-
fn = paw.function(program.id) # reuse with saved program.id
|
|
282
|
-
fn("[step 200] loss=0.04") # "QUIET"
|
|
283
|
-
fn("[Checkpoint] Saved model") # "ALERT"
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
Full tool with file watching, truncation, and stall detection: [examples/paw_monitor.py](https://github.com/programasweights/programasweights-python/blob/main/examples/paw_monitor.py)
|
|
287
|
-
|
|
288
|
-
## Case Studies
|
|
289
|
-
|
|
290
|
-
Detailed walkthroughs of building production systems with PAW, including what we tried and what we learned: [log monitoring](https://programasweights.readthedocs.io/en/latest/case-studies/log-monitoring/), [site navigation](https://programasweights.readthedocs.io/en/latest/case-studies/site-navigation/), [semantic search](https://programasweights.readthedocs.io/en/latest/case-studies/semantic-search/), [tool calling](https://programasweights.readthedocs.io/en/latest/case-studies/tool-calling/).
|
|
291
|
-
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Releasing the Python SDK
|
|
2
|
-
|
|
3
|
-
A release has three separate records: an annotated Git tag identifies the source,
|
|
4
|
-
PyPI serves the installable wheel and source distribution, and a GitHub Release
|
|
5
|
-
shows the version and release notes on the repository. A tag or PyPI upload alone
|
|
6
|
-
does not create a GitHub Release. Finish and verify all three before reporting a
|
|
7
|
-
release complete.
|
|
8
|
-
|
|
9
|
-
## Publish a new version
|
|
10
|
-
|
|
11
|
-
1. Update `pyproject.toml`, the fallback `__version__` in
|
|
12
|
-
`programasweights/__init__.py`, and the matching section in `CHANGELOG.md`.
|
|
13
|
-
Commit and push these changes to `main` using the existing user Git identity.
|
|
14
|
-
Release from a clean checkout of that pushed commit; confirm `HEAD` equals
|
|
15
|
-
`origin/main` and the `tests` workflow is green for that exact commit.
|
|
16
|
-
2. Set the intended version, then build a wheel and source distribution into a
|
|
17
|
-
new, empty directory. Install `build` and `twine` in the release environment if
|
|
18
|
-
needed. Use the two exact filenames below, not a shared `dist/*` directory.
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
SDK_RELEASE_VERSION=0.4.7 # replace with the version being released
|
|
22
|
-
SDK_RELEASE_DIR=$(mktemp -d)
|
|
23
|
-
python -m build --outdir "$SDK_RELEASE_DIR"
|
|
24
|
-
python -m twine check \
|
|
25
|
-
"$SDK_RELEASE_DIR/programasweights-$SDK_RELEASE_VERSION-py3-none-any.whl" \
|
|
26
|
-
"$SDK_RELEASE_DIR/programasweights-$SDK_RELEASE_VERSION.tar.gz"
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
3. Create and push the annotated version tag **before uploading to PyPI**. Check
|
|
30
|
-
that the remote tag resolves to the intended commit and is an annotated tag.
|
|
31
|
-
Never replace an existing release tag with a new target.
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
git tag -a "v$SDK_RELEASE_VERSION" -m "Release v$SDK_RELEASE_VERSION"
|
|
35
|
-
git push origin "v$SDK_RELEASE_VERSION"
|
|
36
|
-
git ls-remote --tags origin "refs/tags/v$SDK_RELEASE_VERSION*"
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
4. Upload the exact wheel and source distribution that passed `twine check`:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
python -m twine upload \
|
|
43
|
-
"$SDK_RELEASE_DIR/programasweights-$SDK_RELEASE_VERSION-py3-none-any.whl" \
|
|
44
|
-
"$SDK_RELEASE_DIR/programasweights-$SDK_RELEASE_VERSION.tar.gz"
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
5. The `release.yml` workflow starts on the `v*` tag push. It waits up to 600
|
|
48
|
-
seconds for PyPI, verifies the remote annotated tag, version metadata, and
|
|
49
|
-
published wheel/source distribution against the tagged source, then creates
|
|
50
|
-
the GitHub Release with notes from that tag's `CHANGELOG.md` and the published
|
|
51
|
-
artifacts. It preserves an existing release and marks a new release as latest
|
|
52
|
-
only when its version is the latest on PyPI. If upload takes longer than the
|
|
53
|
-
wait window, dispatch the workflow again after PyPI publication succeeds.
|
|
54
|
-
6. Verify the workflow succeeded, the GitHub Releases page has the expected entry
|
|
55
|
-
and notes, and the latest-release entry agrees with PyPI's latest version.
|
|
56
|
-
Compare both uploaded files' SHA-256 hashes with the version's PyPI JSON
|
|
57
|
-
(`https://pypi.org/pypi/programasweights/<version>/json`, `urls[].digests.sha256`)
|
|
58
|
-
and with the GitHub Release assets. Do not treat a tag listing as confirmation
|
|
59
|
-
that the release entry exists.
|
|
60
|
-
|
|
61
|
-
## Recover a missing GitHub Release
|
|
62
|
-
|
|
63
|
-
When a version already exists on PyPI, keep its existing tag and published files.
|
|
64
|
-
Do not rebuild or republish that version, and never move its tag. Verify the
|
|
65
|
-
remote annotated tag, matching version metadata and changelog section, and the
|
|
66
|
-
published artifacts first. `scripts/release_metadata.py` requires Python 3.11+
|
|
67
|
-
and performs those checks, preparing the notes and assets in a new directory:
|
|
68
|
-
|
|
69
|
-
```bash
|
|
70
|
-
SDK_RELEASE_RECOVERY_DIR=$(mktemp -d)
|
|
71
|
-
git fetch origin --tags
|
|
72
|
-
python scripts/release_metadata.py --tag v0.4.6 \
|
|
73
|
-
--output-dir "$SDK_RELEASE_RECOVERY_DIR/verified" --wait-seconds 600
|
|
74
|
-
gh workflow run release.yml --ref main -f tag=v0.4.6
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
Replace `v0.4.6` with the verified existing tag to repair. Run this from current
|
|
78
|
-
`main`, which contains the recovery workflow and script; the release content is
|
|
79
|
-
read from the requested tag. The workflow is idempotent: an existing GitHub
|
|
80
|
-
Release is preserved. Recheck the release entry, latest-version status, and
|
|
81
|
-
artifact hashes after it finishes. A source or artifact mismatch needs
|
|
82
|
-
investigation; do not retag or overwrite published artifacts to make it pass.
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# ADR-001: Use llama.cpp instead of PyTorch for SDK runtime
|
|
2
|
-
|
|
3
|
-
## Status: Accepted (2026-03-21)
|
|
4
|
-
|
|
5
|
-
## Context
|
|
6
|
-
|
|
7
|
-
The SDK currently depends on torch + transformers (~2GB install). Users expect a lightweight package they can `pip install` in seconds. Most users run on CPU-only machines (laptops, desktops). The .paw format v2 stores raw safetensors LoRA weights that require PyTorch to apply.
|
|
8
|
-
|
|
9
|
-
## Decision
|
|
10
|
-
|
|
11
|
-
Replace the PyTorch runtime with llama-cpp-python (~80MB install). Use GGUF model format for the base interpreter and Q4_0 quantized GGUF LoRA adapters. Pre-render chat templates server-side so the client needs no tokenizer library.
|
|
12
|
-
|
|
13
|
-
## Consequences
|
|
14
|
-
|
|
15
|
-
- Install size drops from ~2GB to ~80MB (25x reduction)
|
|
16
|
-
- Users no longer need CUDA, PyTorch, or transformers
|
|
17
|
-
- Inference uses Metal (Mac), CPU (Linux/Windows) — no GPU required
|
|
18
|
-
- Must pre-render chat templates server-side (no transformers tokenizer on client)
|
|
19
|
-
- .paw format must change from v2 (safetensors) to v3 (GGUF adapter)
|
|
20
|
-
- Base model is downloaded once (~594 MB Q6_K for Qwen3, ~134 MB Q8_0 for GPT-2) and shared across all functions
|
|
21
|
-
- Per-function adapter download is ~23MB (Q4_0, confirmed lossless at 4096-scale eval)
|