programasweights 0.2.0__py3-none-any.whl → 0.2.2.dev1__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.2.0"
25
+ __version__ = "0.2.2.dev1"
26
26
 
27
27
  from .config import get_api_url, get_api_key, set_api_key
28
28
 
@@ -72,7 +72,7 @@ def compile(
72
72
 
73
73
 
74
74
  def function(
75
- program_id: str,
75
+ program_id,
76
76
  n_ctx: int = 2048,
77
77
  n_gpu_layers: int | None = None,
78
78
  verbose: bool = False,
@@ -83,7 +83,7 @@ def function(
83
83
  Subsequent calls use the local cache.
84
84
 
85
85
  Args:
86
- program_id: The program ID from ``paw.compile()``.
86
+ program_id: Program ID (str), slug, or a ``Program`` object from compile().
87
87
  n_ctx: Context window size for llama.cpp.
88
88
  n_gpu_layers: GPU layers (-1 = all, 0 = CPU only). Defaults to CPU.
89
89
  Set ``PAW_GPU_LAYERS`` env var or pass explicitly for GPU acceleration.
@@ -96,7 +96,12 @@ def function(
96
96
  >>> fn = paw.function("email-triage")
97
97
  >>> fn("Urgent: the server is down!")
98
98
  'immediate'
99
+
100
+ >>> program = paw.compile("Classify sentiment")
101
+ >>> fn = paw.function(program) # accepts Program object directly
99
102
  """
103
+ if hasattr(program_id, 'id'):
104
+ program_id = program_id.slug or program_id.id
100
105
  import os
101
106
  import re
102
107
  from .cache import is_program_cached, get_program_dir, get_cached_slug, save_slug_mapping
@@ -175,9 +180,60 @@ def login(key: str | None = None):
175
180
  print("You can also set the PAW_API_KEY environment variable.")
176
181
 
177
182
 
183
+ def compile_and_load(
184
+ spec: str,
185
+ compiler: str = "paw-4b-qwen3-0.6b",
186
+ n_ctx: int = 2048,
187
+ n_gpu_layers: int | None = None,
188
+ verbose: bool = False,
189
+ **compile_kwargs,
190
+ ):
191
+ """Compile a spec and immediately load it for local inference.
192
+
193
+ Convenience wrapper that combines ``paw.compile()`` and ``paw.function()``
194
+ into a single call.
195
+
196
+ Args:
197
+ spec: Natural language specification.
198
+ compiler: Compiler model name.
199
+ n_ctx: Context window size for llama.cpp.
200
+ n_gpu_layers: GPU layers (-1 = all, 0 = CPU only).
201
+ verbose: Print llama.cpp debug output.
202
+ **compile_kwargs: Additional args passed to compile (slug, public, etc.)
203
+
204
+ Returns:
205
+ A callable ``PawFunction``.
206
+
207
+ Example:
208
+ >>> fn = paw.compile_and_load("Classify sentiment as positive or negative")
209
+ >>> fn("I love this!")
210
+ 'positive'
211
+ """
212
+ program = compile(spec, compiler=compiler, **compile_kwargs)
213
+ return function(program, n_ctx=n_ctx, n_gpu_layers=n_gpu_layers, verbose=verbose)
214
+
215
+
216
+ def list_programs(sort: str = "recent", per_page: int = 20, page: int = 1) -> dict:
217
+ """List your compiled programs. Requires authentication (PAW_API_KEY).
218
+
219
+ Returns:
220
+ Dict with ``programs`` (list), ``total``, ``page``, ``per_page``.
221
+
222
+ Example:
223
+ >>> programs = paw.list_programs()
224
+ >>> for p in programs["programs"]:
225
+ ... print(p["id"], p["name"])
226
+ """
227
+ from .client import PAWClient
228
+ client = PAWClient(api_url=api_url, api_key=api_key)
229
+ return client.list_programs(sort=sort, per_page=per_page, page=page)
230
+
231
+
178
232
  __all__ = [
179
233
  "compile",
234
+ "compile_and_load",
180
235
  "function",
236
+ "list_programs",
181
237
  "login",
182
238
  "api_url",
183
239
  "api_key",
programasweights/cli.py CHANGED
@@ -27,7 +27,8 @@ def cmd_compile(args):
27
27
  if not args.json:
28
28
  print(f"Compiling: {args.spec[:80]}...")
29
29
 
30
- program = paw.compile(args.spec, compiler=args.compiler, slug=getattr(args, 'slug', None))
30
+ public = not getattr(args, 'private', False)
31
+ program = paw.compile(args.spec, compiler=args.compiler, slug=getattr(args, 'slug', None), public=public)
31
32
 
32
33
  if args.json:
33
34
  print(json.dumps({
@@ -170,6 +171,7 @@ def main():
170
171
  p.add_argument("--spec", required=True, help="Natural language specification")
171
172
  p.add_argument("--compiler", default="paw-4b-qwen3-0.6b", help="Compiler model")
172
173
  p.add_argument("--slug", default=None, help="URL-safe handle (e.g. 'message-classifier')")
174
+ p.add_argument("--private", action="store_true", help="Make program private (not listed on hub)")
173
175
  p.add_argument("--json", action="store_true", help="JSON output")
174
176
 
175
177
  p = sub.add_parser("run", help="Run a program locally via llama.cpp")
@@ -108,18 +108,25 @@ class PAWClient:
108
108
  """Download a .paw bundle to the local cache.
109
109
 
110
110
  Returns the path to the extracted program directory.
111
+ Retries on 404 since freshly compiled programs may still be uploading.
111
112
  """
112
113
  program_dir = config.get_programs_dir() / program_id
113
114
  if (program_dir / "prompt_template.txt").exists():
114
115
  return program_dir
115
116
 
116
- resp = httpx.get(
117
- f"{self._api_url}/api/v1/programs/{program_id}/download",
118
- headers=self._headers(),
119
- timeout=60.0,
120
- follow_redirects=True,
121
- )
122
- resp.raise_for_status()
117
+ max_retries = 10
118
+ for attempt in range(max_retries):
119
+ resp = httpx.get(
120
+ f"{self._api_url}/api/v1/programs/{program_id}/download",
121
+ headers=self._headers(),
122
+ timeout=60.0,
123
+ follow_redirects=True,
124
+ )
125
+ if resp.status_code == 404 and attempt < max_retries - 1:
126
+ time.sleep(3)
127
+ continue
128
+ resp.raise_for_status()
129
+ break
123
130
 
124
131
  program_dir.mkdir(parents=True, exist_ok=True)
125
132
  paw_path = program_dir / f"{program_id}.paw"
@@ -140,6 +147,17 @@ class PAWClient:
140
147
  resp.raise_for_status()
141
148
  return resp.json()
142
149
 
150
+ def list_programs(self, sort: str = "recent", per_page: int = 20, page: int = 1) -> dict:
151
+ """List programs for the authenticated user."""
152
+ resp = httpx.get(
153
+ f"{self._api_url}/api/v1/programs",
154
+ params={"mine": "true", "sort": sort, "per_page": per_page, "page": page},
155
+ headers=self._headers(),
156
+ timeout=10.0,
157
+ )
158
+ resp.raise_for_status()
159
+ return resp.json()
160
+
143
161
 
144
162
  _default_client: PAWClient | None = None
145
163
 
@@ -53,12 +53,25 @@ class PawFunction:
53
53
  interpreter = self._meta.get("interpreter", "Qwen/Qwen3-0.6B")
54
54
  base_model_path = cache.get_base_model_path(interpreter)
55
55
 
56
- self._llm = Llama(
57
- model_path=str(base_model_path),
58
- n_ctx=n_ctx,
59
- n_gpu_layers=n_gpu_layers,
60
- verbose=verbose,
61
- )
56
+ if not verbose:
57
+ import os as _os, sys as _sys
58
+ _stderr_fd = _sys.stderr.fileno()
59
+ _devnull = _os.open(_os.devnull, _os.O_WRONLY)
60
+ _old_stderr = _os.dup(_stderr_fd)
61
+ _os.dup2(_devnull, _stderr_fd)
62
+
63
+ try:
64
+ self._llm = Llama(
65
+ model_path=str(base_model_path),
66
+ n_ctx=n_ctx,
67
+ n_gpu_layers=n_gpu_layers,
68
+ verbose=verbose,
69
+ )
70
+ finally:
71
+ if not verbose:
72
+ _os.dup2(_old_stderr, _stderr_fd)
73
+ _os.close(_devnull)
74
+ _os.close(_old_stderr)
62
75
 
63
76
  adapter_path = program_dir / "adapter.gguf"
64
77
  if adapter_path.exists():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programasweights
3
- Version: 0.2.0
3
+ Version: 0.2.2.dev1
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
@@ -1,19 +1,19 @@
1
- programasweights/__init__.py,sha256=W8eI-1fWAOSj-cbUlAehz_dqizS44I_BfKY3Wg2HX08,5947
1
+ programasweights/__init__.py,sha256=8SpAl6BpIBGHy1WsWZQ4EHGnHevzqsjVnMzKoaAjMpo,7852
2
2
  programasweights/artifacts.py,sha256=bSRZgYadAYyuH9aIW6P3VocExfGDGAHeDuj8vod5-Bo,1968
3
3
  programasweights/cache.py,sha256=7L4D5juQLtARVT4aEqzy9N2Lz6xUv9uk7LBZMuJJFrY,3866
4
- programasweights/cli.py,sha256=3r8ggIAvrnCdpT1L0qnQVzw4UBPyv_dh4rTqMT8O26U,6674
5
- programasweights/client.py,sha256=Qk0ubKW54robuVnvEf0AyED5zX2Rw-W4HefBg_GQp8s,4391
4
+ programasweights/cli.py,sha256=X0M3OddGvsBJXjcaKw0qebaU9koe8r30BHgj9Wbf5WM,6840
5
+ programasweights/client.py,sha256=DlgEEgluTZqQJnfYeVh5bW74ZcyxHmrE_3fFgufHsgQ,5153
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
9
- programasweights/runtime_llamacpp.py,sha256=UWcmhKF9iNA2r3gDIKxP5bcdJ2WUvSNilW0_aMfvmuo,6461
9
+ programasweights/runtime_llamacpp.py,sha256=7uuJx6sD1TVu1pj_qikT8CK4_I7aoYvy3UHOc-5gXOM,6929
10
10
  programasweights/compiler/__init__.py,sha256=_q0L02k6Cl9zyvxKQlMuW2o6w7cX6OZ_bZ9wHuZqs18,9508
11
11
  programasweights/compiler/dummy.py,sha256=PcLwijRNM4q2E9PNUcfCPf_y08QjsteVENR0TVsOIfY,1011
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.2.0.dist-info/METADATA,sha256=kOFo-4y367Cnxs7jIFcjoRpvYa5XraK5EJ-EFbtfKY8,5773
16
- programasweights-0.2.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
17
- programasweights-0.2.0.dist-info/entry_points.txt,sha256=l4ZnfCPU0oMzhGB9T2Fv9AnDbSCMM70KUUJVtSvMJBc,50
18
- programasweights-0.2.0.dist-info/licenses/LICENSE,sha256=6GRcDlVhbPMVgkKqBt0cgwyvtvFxpdp4s2vcYKST4r0,1073
19
- programasweights-0.2.0.dist-info/RECORD,,
15
+ programasweights-0.2.2.dev1.dist-info/METADATA,sha256=9EPrwbhEKMuLSLxN1NV_nZpcjiZhDrrLVecdqJFx5zg,5778
16
+ programasweights-0.2.2.dev1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
17
+ programasweights-0.2.2.dev1.dist-info/entry_points.txt,sha256=l4ZnfCPU0oMzhGB9T2Fv9AnDbSCMM70KUUJVtSvMJBc,50
18
+ programasweights-0.2.2.dev1.dist-info/licenses/LICENSE,sha256=6GRcDlVhbPMVgkKqBt0cgwyvtvFxpdp4s2vcYKST4r0,1073
19
+ programasweights-0.2.2.dev1.dist-info/RECORD,,