programasweights 0.1.0.dev7__py3-none-any.whl → 0.1.0.dev9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,7 @@ API reference:
22
22
  paw.api_key API key (set via login() or PAW_API_KEY env var)
23
23
  """
24
24
 
25
- __version__ = "0.1.0.dev7"
25
+ __version__ = "0.1.0.dev9"
26
26
 
27
27
  from .config import get_api_url, get_api_key, set_api_key
28
28
 
@@ -37,33 +37,38 @@ def compile(
37
37
  name: str | None = None,
38
38
  tags: list[str] | None = None,
39
39
  public: bool = True,
40
+ slug: str | None = None,
40
41
  ):
41
42
  """Compile a natural language specification into a neural program.
42
43
 
43
44
  The compilation runs on the PAW server. The resulting program can be
44
- downloaded and run locally via ``paw.function(program.id)``.
45
+ downloaded and run locally via ``paw.function(program.id)`` or
46
+ ``paw.function(program.slug)`` if a slug was provided.
45
47
 
46
48
  Args:
47
49
  spec: Full specification text. Include examples in the text if desired.
48
50
  compiler: Compiler model (alias or snapshot name).
49
- name: Human-readable program name for the hub.
51
+ name: Human-readable program name (display title for the hub).
50
52
  tags: Tags for hub discovery.
51
53
  public: Whether to list on the public hub.
54
+ slug: URL-safe handle (e.g. 'message-classifier'). Creates a
55
+ ``username/slug`` alias. Requires authentication.
52
56
 
53
57
  Returns:
54
- A ``Program`` object with ``id``, ``status``, and ``timings``.
58
+ A ``Program`` object with ``id``, ``slug``, ``status``, and ``timings``.
55
59
 
56
60
  Example:
57
61
  >>> program = paw.compile(
58
- ... "Fix malformed JSON: repair missing quotes and trailing commas"
62
+ ... "Fix malformed JSON: repair missing quotes and trailing commas",
63
+ ... slug="json-fixer"
59
64
  ... )
60
- >>> fn = paw.function(program.id)
65
+ >>> fn = paw.function(program.slug) # or paw.function(program.id)
61
66
  >>> fn("{name: 'Alice',}")
62
67
  '{"name": "Alice"}'
63
68
  """
64
69
  from .client import PAWClient
65
70
  client = PAWClient(api_url=api_url, api_key=api_key)
66
- return client.compile(spec, compiler=compiler, name=name, tags=tags, public=public)
71
+ return client.compile(spec, compiler=compiler, name=name, tags=tags, public=public, slug=slug)
67
72
 
68
73
 
69
74
  def function(
@@ -94,7 +99,7 @@ def function(
94
99
  """
95
100
  import os
96
101
  import re
97
- from .cache import is_program_cached, get_program_dir
102
+ from .cache import is_program_cached, get_program_dir, get_cached_slug, save_slug_mapping
98
103
  from .runtime_llamacpp import PawFunction
99
104
 
100
105
  if n_gpu_layers is None:
@@ -102,9 +107,14 @@ def function(
102
107
 
103
108
  resolved_id = program_id
104
109
  if not re.fullmatch(r"[a-f0-9]{16,64}", program_id):
105
- from .client import PAWClient
106
- client = PAWClient(api_url=api_url, api_key=api_key)
107
- resolved_id = client.resolve_slug(program_id)
110
+ cached = get_cached_slug(program_id)
111
+ if cached:
112
+ resolved_id = cached
113
+ else:
114
+ from .client import PAWClient
115
+ client = PAWClient(api_url=api_url, api_key=api_key)
116
+ resolved_id = client.resolve_slug(program_id)
117
+ save_slug_mapping(program_id, resolved_id)
108
118
 
109
119
  if not is_program_cached(resolved_id):
110
120
  from .client import PAWClient
programasweights/cache.py CHANGED
@@ -10,10 +10,12 @@ Cache structure:
10
10
  adapter.gguf # ~23 MB, Q4_0 LoRA
11
11
  prompt_template.txt
12
12
  meta.json
13
+ slug_cache.json # slug -> program_id mapping
13
14
  """
14
15
 
15
16
  from __future__ import annotations
16
17
 
18
+ import json
17
19
  import os
18
20
  from pathlib import Path
19
21
 
@@ -80,3 +82,36 @@ def _download_file(url: str, dest: Path):
80
82
  mb = downloaded / 1024 / 1024
81
83
  print(f"\r {mb:.1f} MB ({pct:.0f}%)", end="", flush=True)
82
84
  print()
85
+
86
+
87
+ def _slug_cache_path() -> Path:
88
+ return config.get_cache_dir() / "slug_cache.json"
89
+
90
+
91
+ def get_cached_slug(slug: str) -> str | None:
92
+ """Look up a slug in the local cache. Returns program_id or None."""
93
+ path = _slug_cache_path()
94
+ if not path.exists():
95
+ return None
96
+ try:
97
+ data = json.loads(path.read_text())
98
+ program_id = data.get(slug)
99
+ if program_id and is_program_cached(program_id):
100
+ return program_id
101
+ except (json.JSONDecodeError, OSError):
102
+ pass
103
+ return None
104
+
105
+
106
+ def save_slug_mapping(slug: str, program_id: str) -> None:
107
+ """Save a slug -> program_id mapping to the local cache."""
108
+ path = _slug_cache_path()
109
+ data: dict = {}
110
+ if path.exists():
111
+ try:
112
+ data = json.loads(path.read_text())
113
+ except (json.JSONDecodeError, OSError):
114
+ pass
115
+ data[slug] = program_id
116
+ path.parent.mkdir(parents=True, exist_ok=True)
117
+ path.write_text(json.dumps(data))
programasweights/cli.py CHANGED
@@ -26,11 +26,12 @@ def cmd_compile(args):
26
26
  if not args.json:
27
27
  print(f"Compiling: {args.spec[:80]}...")
28
28
 
29
- program = paw.compile(args.spec, compiler=args.compiler)
29
+ program = paw.compile(args.spec, compiler=args.compiler, slug=getattr(args, 'slug', None))
30
30
 
31
31
  if args.json:
32
32
  print(json.dumps({
33
33
  "program_id": program.id,
34
+ "slug": program.slug,
34
35
  "status": program.status,
35
36
  "error": program.error,
36
37
  "timings": program.timings,
@@ -42,15 +43,18 @@ def cmd_compile(args):
42
43
  return 1
43
44
 
44
45
  print(f"Program ID: {program.id}")
46
+ if program.slug:
47
+ print(f"Slug: {program.slug}")
45
48
  print(f"Status: {program.status}")
46
49
  if program.timings:
47
50
  total = program.timings.get("total_ms", 0)
48
51
  print(f"Total time: {total:.0f}ms")
52
+ ref = program.slug or program.id
49
53
  print(f"\nTo run locally:")
50
- print(f" paw run {program.id} \"your input here\"")
54
+ print(f" paw run --program \"{ref}\" --input \"your input here\"")
51
55
  print(f"\nOr in Python:")
52
56
  print(f" import programasweights as paw")
53
- print(f" fn = paw.function(\"{program.id}\")")
57
+ print(f" fn = paw.function(\"{ref}\")")
54
58
  print(f" fn(\"your input here\")")
55
59
  return 0
56
60
 
@@ -80,6 +84,37 @@ def cmd_login(args):
80
84
  return 0
81
85
 
82
86
 
87
+ def cmd_rename(args):
88
+ import programasweights as paw
89
+ if args.api_url:
90
+ paw.api_url = args.api_url
91
+ if args.api_key:
92
+ paw.api_key = args.api_key
93
+
94
+ import httpx
95
+ from programasweights.client import PAWClient
96
+ client = PAWClient(api_url=paw.api_url, api_key=paw.api_key)
97
+
98
+ resp = httpx.patch(
99
+ f"{client._api_url}/api/v1/programs/{args.program}",
100
+ json={"slug": args.new_slug},
101
+ headers=client._headers(),
102
+ timeout=10.0,
103
+ )
104
+ resp.raise_for_status()
105
+ data = resp.json()
106
+
107
+ if args.json:
108
+ print(json.dumps(data))
109
+ else:
110
+ slug = data.get("slug")
111
+ if slug:
112
+ print(f"Renamed to: {slug}")
113
+ else:
114
+ print("Slug removed.")
115
+ return 0
116
+
117
+
83
118
  def cmd_info(args):
84
119
  import programasweights as paw
85
120
  if args.api_url:
@@ -129,6 +164,7 @@ def main():
129
164
  p = sub.add_parser("compile", help="Compile a spec on the server")
130
165
  p.add_argument("--spec", required=True, help="Natural language specification")
131
166
  p.add_argument("--compiler", default="paw-4b-qwen3-0.6b", help="Compiler model")
167
+ p.add_argument("--slug", default=None, help="URL-safe handle (e.g. 'message-classifier')")
132
168
  p.add_argument("--json", action="store_true", help="JSON output")
133
169
 
134
170
  p = sub.add_parser("run", help="Run a program locally via llama.cpp")
@@ -142,6 +178,11 @@ def main():
142
178
  p = sub.add_parser("login", help="Save API key for authentication")
143
179
  p.add_argument("key", nargs="?", default=None, help="API key (paw_sk_...). Omit to open browser.")
144
180
 
181
+ p = sub.add_parser("rename", help="Set or change a program's slug")
182
+ p.add_argument("program", help="Program ID or current slug")
183
+ p.add_argument("new_slug", help="New slug (e.g. 'message-classifier') or empty string to remove")
184
+ p.add_argument("--json", action="store_true", help="JSON output")
185
+
145
186
  p = sub.add_parser("info", help="Show program info")
146
187
  p.add_argument("program", help="Program name or ID")
147
188
  p.add_argument("--json", action="store_true", help="JSON output")
@@ -156,6 +197,7 @@ def main():
156
197
  "compile": cmd_compile,
157
198
  "run": cmd_run,
158
199
  "login": cmd_login,
200
+ "rename": cmd_rename,
159
201
  "info": cmd_info,
160
202
  }
161
203
 
@@ -23,6 +23,7 @@ class Program:
23
23
  """Result of a compilation."""
24
24
  id: str
25
25
  status: str
26
+ slug: Optional[str] = None
26
27
  compiler_snapshot: Optional[str] = None
27
28
  timings: Optional[dict] = None
28
29
  error: Optional[str] = None
@@ -48,27 +49,32 @@ class PAWClient:
48
49
  name: str | None = None,
49
50
  tags: list[str] | None = None,
50
51
  public: bool = True,
52
+ slug: str | None = None,
51
53
  ) -> Program:
52
54
  """Compile a spec into a neural program on the server.
53
55
 
54
56
  Args:
55
57
  spec: Natural language specification. Include examples in the text.
56
58
  compiler: Compiler name (alias or snapshot).
57
- name: Human-readable program name.
59
+ name: Human-readable program name (display title).
58
60
  tags: Tags for hub discovery.
59
61
  public: Whether to list on the public hub.
62
+ slug: URL-safe handle (e.g. 'message-classifier'). Creates a
63
+ ``username/slug`` alias for easy reference. Requires auth.
60
64
 
61
65
  Returns:
62
- Program with id, status, and timings.
66
+ Program with id, slug, status, and timings.
63
67
 
64
68
  Raises:
65
69
  httpx.HTTPStatusError: On API errors (422 for validation, 429 for rate limit).
66
70
  """
67
- body = {"spec": spec, "compiler": compiler, "public": public}
71
+ body: dict = {"spec": spec, "compiler": compiler, "public": public}
68
72
  if name:
69
73
  body["name"] = name
70
74
  if tags:
71
75
  body["tags"] = tags
76
+ if slug:
77
+ body["slug"] = slug
72
78
 
73
79
  resp = httpx.post(
74
80
  f"{self._api_url}/api/v1/compile",
@@ -82,6 +88,7 @@ class PAWClient:
82
88
  return Program(
83
89
  id=data.get("program_id", ""),
84
90
  status=data.get("status", "unknown"),
91
+ slug=data.get("slug"),
85
92
  compiler_snapshot=data.get("compiler_snapshot"),
86
93
  timings=data.get("timings"),
87
94
  error=data.get("error"),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programasweights
3
- Version: 0.1.0.dev7
3
+ Version: 0.1.0.dev9
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
@@ -22,7 +22,7 @@ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
22
22
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
23
  Requires-Python: >=3.9
24
24
  Requires-Dist: httpx<1.0,>=0.27.0
25
- Requires-Dist: llama-cpp-python<1.0,>=0.3.0
25
+ Requires-Dist: llama-cpp-python<=0.3.18,>=0.3.0
26
26
  Provides-Extra: test
27
27
  Requires-Dist: pytest; extra == 'test'
28
28
  Description-Content-Type: text/markdown
@@ -60,7 +60,7 @@ fn("{name: 'Alice',}") # '{"name": "Alice"}'
60
60
 
61
61
  ## Two Compilers
62
62
 
63
- | | Qwen3 0.6B | GPT-2 124M |
63
+ | | Standard (Qwen3 0.6B) | Compact (GPT-2 124M) |
64
64
  |--------------------|-------------------------|------------------------|
65
65
  | Compiler name | `paw-4b-qwen3-0.6b` | `paw-4b-gpt2` |
66
66
  | Accuracy | Higher | Lower |
@@ -69,7 +69,7 @@ fn("{name: 'Alice',}") # '{"name": "Alice"}'
69
69
  | Inference speed | ~90ms (server) | ~50ms (server) |
70
70
  | Runs in browser | No | Yes |
71
71
 
72
- Default is Qwen3 0.6B. Use GPT-2 when you need smaller files or browser deployment.
72
+ Default is Standard (Qwen3 0.6B). Use Compact (GPT-2) when you need smaller files or browser deployment.
73
73
 
74
74
  ## Browser SDK
75
75
 
@@ -104,6 +104,7 @@ Or save [`AGENTS.md`](https://programasweights.com/agents) to your project root
104
104
  - **Classification** — sentiment, urgency, categories defined in your own words
105
105
  - **Extraction** — emails, names, dates from messy unstructured text
106
106
  - **Log triage** — extract errors from verbose output, filter noise
107
+ - **Intent routing** — map user descriptions to the closest URL, menu item, or setting
107
108
  - **Agent preprocessing** — parse tool calls, validate outputs, route tasks
108
109
 
109
110
  ## Authentication
@@ -1,8 +1,8 @@
1
- programasweights/__init__.py,sha256=e_IusOtFtLEunVj5N3Go3cpwQpVD0lS48v9i0cufiQk,5412
1
+ programasweights/__init__.py,sha256=b1St5bbuKs0dXCYGiMEsqUrs2zbNyGoqvmgN11qkOvg,5952
2
2
  programasweights/artifacts.py,sha256=bSRZgYadAYyuH9aIW6P3VocExfGDGAHeDuj8vod5-Bo,1968
3
- programasweights/cache.py,sha256=UXGG9ihckmUKo43ECI9w8GYx9nl4moHCq4NAcSmsYi8,2656
4
- programasweights/cli.py,sha256=n40CQH9SbovYnHQl4k3CY1TqOzMlRqBFksgBsEiEr5Q,5117
5
- programasweights/client.py,sha256=1IAl1YL4P2wNbcVpy2cDqL4WjCL3Z2T1orNIXDtcrrw,4067
3
+ programasweights/cache.py,sha256=69mOsx2Aqi3sQjFXjeBvhKySXDKdvKSINis2FprVDw4,3711
4
+ programasweights/cli.py,sha256=_HCBRXfn9at7a4oTvVOAi2lPMMKaDxleLngdc6WKi2c,6480
5
+ programasweights/client.py,sha256=Qk0ubKW54robuVnvEf0AyED5zX2Rw-W4HefBg_GQp8s,4391
6
6
  programasweights/config.py,sha256=zQFnVNfYR4bFx2DsZheMnPy2yd9T4-fe0u2sG1GluE8,1553
7
7
  programasweights/convert_peft_to_paw.py,sha256=yvavaAzLUqc-lFHEC_9AOhsuI-fCobu6k-GDMVQdOHk,6521
8
8
  programasweights/paw_format.py,sha256=wRXolwtnPgKoopiJC8-yMVZZtiwB-PoAqaWpDFKMoj8,10679
@@ -12,7 +12,7 @@ programasweights/compiler/dummy.py,sha256=PcLwijRNM4q2E9PNUcfCPf_y08QjsteVENR0TV
12
12
  programasweights/runtime/__init__.py,sha256=S4jp7-eWAcMa0X417U7P6HkTL1j3v8ffQA-nneh9wY0,549
13
13
  programasweights/runtime/interpreter.py,sha256=brYCtatSsu23lq87cuki4MViqZX6U32LBw7Z3USbQmA,19632
14
14
  programasweights/runtime/interpreter_onnx.py,sha256=kzYKmwg_h0tVhoQlixJGKoHPVhcCK22AcHG59oeYX2Q,21559
15
- programasweights-0.1.0.dev7.dist-info/METADATA,sha256=PdAZEpqWs9cGdy2gaFLiNo3jaDyp9ZtVSvkGVHJStNw,5464
16
- programasweights-0.1.0.dev7.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
17
- programasweights-0.1.0.dev7.dist-info/entry_points.txt,sha256=l4ZnfCPU0oMzhGB9T2Fv9AnDbSCMM70KUUJVtSvMJBc,50
18
- programasweights-0.1.0.dev7.dist-info/RECORD,,
15
+ programasweights-0.1.0.dev9.dist-info/METADATA,sha256=1WwaxDSpm7CGFxuzkCQcxlntjEnFrfmNBaN9p9oFHO8,5578
16
+ programasweights-0.1.0.dev9.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
17
+ programasweights-0.1.0.dev9.dist-info/entry_points.txt,sha256=l4ZnfCPU0oMzhGB9T2Fv9AnDbSCMM70KUUJVtSvMJBc,50
18
+ programasweights-0.1.0.dev9.dist-info/RECORD,,