wsm 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.
Files changed (40) hide show
  1. wsm-0.1.0/PKG-INFO +50 -0
  2. wsm-0.1.0/README.md +27 -0
  3. wsm-0.1.0/pyproject.toml +27 -0
  4. wsm-0.1.0/setup.cfg +4 -0
  5. wsm-0.1.0/src/wsm/__init__.py +14 -0
  6. wsm-0.1.0/src/wsm/__main__.py +3 -0
  7. wsm-0.1.0/src/wsm/_publication.py +19 -0
  8. wsm-0.1.0/src/wsm/cli.py +78 -0
  9. wsm-0.1.0/src/wsm/coding_tui.py +79 -0
  10. wsm-0.1.0/src/wsm/editing.py +394 -0
  11. wsm-0.1.0/src/wsm/errors.py +7 -0
  12. wsm-0.1.0/src/wsm/modal_trial.py +162 -0
  13. wsm-0.1.0/src/wsm/program.py +213 -0
  14. wsm-0.1.0/src/wsm/trial.py +248 -0
  15. wsm-0.1.0/src/wsm/trial_distillation.py +197 -0
  16. wsm-0.1.0/src/wsm/trial_editor.py +89 -0
  17. wsm-0.1.0/src/wsm/trial_grading.py +84 -0
  18. wsm-0.1.0/src/wsm/trial_poc.py +422 -0
  19. wsm-0.1.0/src/wsm/trial_training.py +261 -0
  20. wsm-0.1.0/src/wsm/trial_transport.py +188 -0
  21. wsm-0.1.0/src/wsm/trial_worker.py +81 -0
  22. wsm-0.1.0/src/wsm/tui.py +110 -0
  23. wsm-0.1.0/src/wsm.egg-info/PKG-INFO +50 -0
  24. wsm-0.1.0/src/wsm.egg-info/SOURCES.txt +38 -0
  25. wsm-0.1.0/src/wsm.egg-info/dependency_links.txt +1 -0
  26. wsm-0.1.0/src/wsm.egg-info/entry_points.txt +2 -0
  27. wsm-0.1.0/src/wsm.egg-info/requires.txt +18 -0
  28. wsm-0.1.0/src/wsm.egg-info/top_level.txt +1 -0
  29. wsm-0.1.0/tests/test_cli.py +34 -0
  30. wsm-0.1.0/tests/test_coding_tui.py +25 -0
  31. wsm-0.1.0/tests/test_editing.py +255 -0
  32. wsm-0.1.0/tests/test_modal_trial.py +61 -0
  33. wsm-0.1.0/tests/test_program.py +270 -0
  34. wsm-0.1.0/tests/test_spindle_owner.py +43 -0
  35. wsm-0.1.0/tests/test_trial.py +121 -0
  36. wsm-0.1.0/tests/test_trial_distillation.py +158 -0
  37. wsm-0.1.0/tests/test_trial_editor.py +117 -0
  38. wsm-0.1.0/tests/test_trial_poc.py +222 -0
  39. wsm-0.1.0/tests/test_trial_spindle.py +53 -0
  40. wsm-0.1.0/tests/test_trial_training.py +154 -0
wsm-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,50 @@
1
+ Metadata-Version: 2.4
2
+ Name: wsm
3
+ Version: 0.1.0
4
+ Summary: WSM (Weight Space Mods): Python model weight editing
5
+ Project-URL: Repository, https://github.com/thoriqakbar0/wsm
6
+ Project-URL: Documentation, https://github.com/thoriqakbar0/wsm/blob/main/README.md
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ Provides-Extra: tinker
10
+ Requires-Dist: tinker==0.39.0; extra == "tinker"
11
+ Provides-Extra: trial
12
+ Requires-Dist: modal==1.6.3; extra == "trial"
13
+ Requires-Dist: tinker==0.39.0; extra == "trial"
14
+ Requires-Dist: jinja2>=3.1.6; extra == "trial"
15
+ Provides-Extra: spindle
16
+ Requires-Dist: modal==1.6.3; extra == "spindle"
17
+ Requires-Dist: tinker==0.39.0; extra == "spindle"
18
+ Requires-Dist: jinja2>=3.1.6; extra == "spindle"
19
+ Provides-Extra: editing
20
+ Requires-Dist: torch; extra == "editing"
21
+ Requires-Dist: transformers; extra == "editing"
22
+ Requires-Dist: safetensors; extra == "editing"
23
+
24
+ # WSM (Weight Space Mods)
25
+
26
+ WSM is a Python SDK for model weight editing. Access named tensors, change weights, evaluate the result, and save a standalone checkpoint.
27
+
28
+ Requires Python 3.12 or later. The core package has no third-party runtime dependencies.
29
+
30
+ ```sh
31
+ pip install wsm
32
+ wsm --help
33
+ ```
34
+
35
+ Install the model dependencies to load a local snapshot:
36
+
37
+ ```sh
38
+ pip install 'wsm[editing]'
39
+ ```
40
+
41
+ ```python
42
+ from wsm import WeightModel
43
+
44
+ model = WeightModel.load("/path/to/local/snapshot")
45
+ model.weights["model.norm.weight"][:16].mul_(0.95)
46
+ result = model.evaluate([{"prompt": "Say hello.", "target": "Hello!"}])
47
+ model.save("/path/to/new-checkpoint")
48
+ ```
49
+
50
+ The supported Python API consists of `WeightModel` and `execute_program`. Read the [project documentation](https://github.com/thoriqakbar0/wsm#readme) for CLI usage, execution trust, and optional Modal and Spindle trials. Spindle requires a separate pinned source installation documented in the [trial guide](https://github.com/thoriqakbar0/wsm/blob/main/docs/trials.md).
wsm-0.1.0/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # WSM (Weight Space Mods)
2
+
3
+ WSM is a Python SDK for model weight editing. Access named tensors, change weights, evaluate the result, and save a standalone checkpoint.
4
+
5
+ Requires Python 3.12 or later. The core package has no third-party runtime dependencies.
6
+
7
+ ```sh
8
+ pip install wsm
9
+ wsm --help
10
+ ```
11
+
12
+ Install the model dependencies to load a local snapshot:
13
+
14
+ ```sh
15
+ pip install 'wsm[editing]'
16
+ ```
17
+
18
+ ```python
19
+ from wsm import WeightModel
20
+
21
+ model = WeightModel.load("/path/to/local/snapshot")
22
+ model.weights["model.norm.weight"][:16].mul_(0.95)
23
+ result = model.evaluate([{"prompt": "Say hello.", "target": "Hello!"}])
24
+ model.save("/path/to/new-checkpoint")
25
+ ```
26
+
27
+ The supported Python API consists of `WeightModel` and `execute_program`. Read the [project documentation](https://github.com/thoriqakbar0/wsm#readme) for CLI usage, execution trust, and optional Modal and Spindle trials. Spindle requires a separate pinned source installation documented in the [trial guide](https://github.com/thoriqakbar0/wsm/blob/main/docs/trials.md).
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "wsm"
7
+ version = "0.1.0"
8
+ description = "WSM (Weight Space Mods): Python model weight editing"
9
+ readme = "README.md"
10
+ requires-python = ">=3.12"
11
+ dependencies = []
12
+
13
+ [project.urls]
14
+ Repository = "https://github.com/thoriqakbar0/wsm"
15
+ Documentation = "https://github.com/thoriqakbar0/wsm/blob/main/README.md"
16
+
17
+ [project.scripts]
18
+ wsm = "wsm.cli:main"
19
+
20
+ [project.optional-dependencies]
21
+ tinker = ["tinker==0.39.0"]
22
+ trial = ["modal==1.6.3", "tinker==0.39.0", "jinja2>=3.1.6"]
23
+ spindle = ["modal==1.6.3", "tinker==0.39.0", "jinja2>=3.1.6"]
24
+ editing = ["torch", "transformers", "safetensors"]
25
+
26
+ [tool.setuptools.packages.find]
27
+ where = ["src"]
wsm-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,14 @@
1
+ """Python tools for editing, evaluating, and saving model weights."""
2
+
3
+ __version__ = "0.1.0"
4
+ __all__ = ["WeightModel", "execute_program"]
5
+
6
+
7
+ def __getattr__(name):
8
+ if name == "WeightModel":
9
+ from .editing import WeightModel
10
+ return WeightModel
11
+ if name == "execute_program":
12
+ from .program import execute_program
13
+ return execute_program
14
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ raise SystemExit(main())
@@ -0,0 +1,19 @@
1
+ """Atomic checkpoint publication without replacing an existing destination."""
2
+ import ctypes
3
+ import errno
4
+ import os
5
+
6
+ from .errors import WeightlessError
7
+
8
+
9
+ def _publish(source, destination):
10
+ rename = getattr(ctypes.CDLL(None, use_errno=True), "renameat2", None)
11
+ if rename is None:
12
+ raise WeightlessError("unsupported_platform", "Atomic exclusive export requires renameat2")
13
+ rename.argtypes = [ctypes.c_int, ctypes.c_char_p, ctypes.c_int, ctypes.c_char_p, ctypes.c_uint]
14
+ rename.restype = ctypes.c_int
15
+ if rename(-100, os.fsencode(source), -100, os.fsencode(destination), 1) != 0:
16
+ code = ctypes.get_errno()
17
+ if code in (errno.EEXIST, errno.ENOTEMPTY):
18
+ raise WeightlessError("export_exists", "Destination already exists")
19
+ raise OSError(code, os.strerror(code), str(destination))
@@ -0,0 +1,78 @@
1
+ """Commands for trusted Python weight editing."""
2
+ import argparse
3
+ import json
4
+ from pathlib import Path
5
+ import sys
6
+
7
+ from . import __version__
8
+ from .errors import WeightlessError
9
+
10
+
11
+ def parser():
12
+ root = argparse.ArgumentParser(prog="wsm", description="Edit model weights with trusted Python. No command opens the TUI.")
13
+ root.add_argument('--version', action='version', version=f'wsm {__version__}')
14
+ commands = root.add_subparsers(dest='command')
15
+ execute = commands.add_parser('execute', help='Execute a trusted Python file defining edit(model)')
16
+ execute.add_argument('program', type=Path)
17
+ execute.add_argument('--model', type=Path, required=True)
18
+ execute.add_argument('--output', type=Path, required=True)
19
+ execute.add_argument('--cases', type=Path, required=True)
20
+ execute.add_argument('--device', default='cpu')
21
+ commands.add_parser('tui', help='Open the Python editing terminal')
22
+ trial = commands.add_parser("trial", help="Run or watch an experimental Modal coding trial")
23
+ trial_commands = trial.add_subparsers(dest="trial_command", required=True)
24
+ preflight = trial_commands.add_parser("preflight", help="Validate explicit task, policy, and price configuration offline")
25
+ preflight.add_argument("--config", type=Path, required=True)
26
+ trial_run = trial_commands.add_parser("run", help="Run one fixed-model Modal trial and hosted Tinker update")
27
+ trial_run.add_argument("--config", type=Path, required=True)
28
+ trial_run.add_argument("--output", type=Path, required=True)
29
+ trial_view = trial_commands.add_parser("view", help="Read the public trial journal without control access")
30
+ trial_view.add_argument("directory", type=Path)
31
+ trial_view.add_argument("--follow", action="store_true")
32
+ weights = trial_commands.add_parser("weights", help="Read retained tensor shapes or numerical values")
33
+ weights.add_argument("checkpoint", type=Path, help="Retained safetensors file")
34
+ weights.add_argument("--tensor")
35
+ weights.add_argument("--indices", type=int, nargs="+")
36
+ return root
37
+
38
+
39
+ def main(argv=None):
40
+ args = parser().parse_args(argv)
41
+ try:
42
+ if args.command == "trial":
43
+ from .trial_poc import inspect_weights, load_config, run_poc, watch
44
+ if args.trial_command == "view":
45
+ watch(args.directory, follow=args.follow)
46
+ elif args.trial_command == "weights":
47
+ print(json.dumps(inspect_weights(args.checkpoint, tensor=args.tensor, indices=args.indices),
48
+ indent=2, allow_nan=False))
49
+ else:
50
+ config = load_config(args.config)
51
+ result = ({"valid": True, "cloud_calls": 0, "budget_usd": config["budget"]["max_usd"]}
52
+ if args.trial_command == "preflight" else run_poc(config, args.output))
53
+ print(json.dumps(result, indent=2, allow_nan=False))
54
+ return 0
55
+ if args.command in (None, 'tui'):
56
+ if not sys.stdin.isatty() or not sys.stdout.isatty():
57
+ raise WeightlessError('terminal_required', 'The TUI requires a terminal; use --help for scriptable commands')
58
+ from .tui import launch
59
+ return launch()
60
+ from .program import execute_program
61
+ cases = json.loads(args.cases.read_text())
62
+ result = execute_program(args.program, model_path=args.model, output=args.output,
63
+ device=args.device, cases=cases)
64
+ print(json.dumps(result, allow_nan=False, indent=2))
65
+ return 0 if result.get('state') == 'published' else 1
66
+ except KeyboardInterrupt:
67
+ message = (f"Interrupted. Inspect {args.output / 'run.json'} and its checkpoint before retrying."
68
+ if args.command == 'execute' else 'Interrupted.')
69
+ print(json.dumps({'error': {'code': 'interrupted', 'message': message}}), file=sys.stderr)
70
+ return 130
71
+ except (Exception, SystemExit) as error:
72
+ print(json.dumps({'error': {'code': getattr(error, 'code', 'execution_error'),
73
+ 'type': type(error).__name__, 'message': str(error)}}), file=sys.stderr)
74
+ return 1
75
+
76
+
77
+ if __name__ == '__main__':
78
+ raise SystemExit(main())
@@ -0,0 +1,79 @@
1
+ """Terminal controls for the same Python execution command used by coding agents."""
2
+ import curses
3
+ import json
4
+ import os
5
+ from pathlib import Path
6
+ import signal
7
+ import subprocess
8
+ import sys
9
+ import tempfile
10
+
11
+
12
+ def stop(process, first_signal):
13
+ try:
14
+ os.killpg(process.pid, first_signal)
15
+ except ProcessLookupError:
16
+ pass
17
+ try:
18
+ process.wait(timeout=10)
19
+ except subprocess.TimeoutExpired:
20
+ pass
21
+ finally:
22
+ try:
23
+ os.killpg(process.pid, signal.SIGKILL)
24
+ except ProcessLookupError:
25
+ pass
26
+ process.wait(timeout=10)
27
+
28
+
29
+ def execute(screen):
30
+ from .tui import prompt, put, show_result
31
+
32
+ program = Path(prompt(screen, "Python editing file defining edit(model)")).expanduser().resolve()
33
+ show_result(screen, "Review Python source before execution", program.read_text().splitlines())
34
+ model = Path(prompt(screen, "Local model snapshot directory")).expanduser().resolve()
35
+ cases = Path(prompt(screen, "Public evaluation cases JSON")).expanduser().resolve()
36
+ output = Path(prompt(screen, "New output directory")).expanduser().resolve()
37
+ device = prompt(screen, "Torch device", default="cpu")
38
+ command = [sys.executable, "-m", "wsm", "execute", str(program), "--model", str(model),
39
+ "--cases", str(cases), "--output", str(output), "--device", device]
40
+ process = None
41
+ with tempfile.TemporaryFile(mode="w+b") as log:
42
+ try:
43
+ process = subprocess.Popen(command, stdin=subprocess.DEVNULL, stdout=log,
44
+ stderr=subprocess.STDOUT, start_new_session=True)
45
+ screen.timeout(100)
46
+ while process.poll() is None:
47
+ screen.erase()
48
+ put(screen, 1, "WSM / execute Python", attr=curses.A_BOLD)
49
+ put(screen, 3, str(program))
50
+ state = "starting"
51
+ try:
52
+ state = json.loads((output / "run.json").read_text()).get("state", state)
53
+ except (OSError, ValueError):
54
+ pass
55
+ put(screen, 5, "State " + state)
56
+ put(screen, 7, "Output " + str(output))
57
+ put(screen, 9, "Ctrl-C interrupts execution. Publication is recorded in run.json.")
58
+ screen.refresh()
59
+ try:
60
+ screen.get_wch()
61
+ except curses.error:
62
+ pass
63
+ except KeyboardInterrupt:
64
+ if process is not None:
65
+ stop(process, signal.SIGINT)
66
+ finally:
67
+ screen.timeout(-1)
68
+ if process is not None:
69
+ stop(process, signal.SIGTERM)
70
+ log.seek(0, 2)
71
+ log.seek(max(0, log.tell() - 16000))
72
+ text = log.read(16000).decode('utf-8', errors='replace')
73
+ try:
74
+ result = json.loads((output / "run.json").read_text())
75
+ except (OSError, ValueError):
76
+ result = {"state": "unknown", "output": str(output),
77
+ "detail": "Inspect output before retrying. No completion receipt was readable."}
78
+ show_result(screen, "Python execution result", {"run": result, "process_output": text})
79
+ return result