neuralosd 1.0.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 (47) hide show
  1. neuralosd-1.0.0/PKG-INFO +151 -0
  2. neuralosd-1.0.0/README.md +114 -0
  3. neuralosd-1.0.0/pyproject.toml +44 -0
  4. neuralosd-1.0.0/setup.cfg +4 -0
  5. neuralosd-1.0.0/src/neuralosd/__init__.py +24 -0
  6. neuralosd-1.0.0/src/neuralosd/_cmd/__init__.py +0 -0
  7. neuralosd-1.0.0/src/neuralosd/_cmd/ask.py +7 -0
  8. neuralosd-1.0.0/src/neuralosd/_cmd/calibrate.py +13 -0
  9. neuralosd-1.0.0/src/neuralosd/_cmd/diff.py +13 -0
  10. neuralosd-1.0.0/src/neuralosd/_cmd/gaps.py +13 -0
  11. neuralosd-1.0.0/src/neuralosd/_cmd/golden.py +13 -0
  12. neuralosd-1.0.0/src/neuralosd/_cmd/init.py +21 -0
  13. neuralosd-1.0.0/src/neuralosd/_cmd/invariants.py +13 -0
  14. neuralosd-1.0.0/src/neuralosd/_cmd/lint.py +8 -0
  15. neuralosd-1.0.0/src/neuralosd/_cmd/openapi.py +13 -0
  16. neuralosd-1.0.0/src/neuralosd/_cmd/serve.py +5 -0
  17. neuralosd-1.0.0/src/neuralosd/_cmd/truth.py +13 -0
  18. neuralosd-1.0.0/src/neuralosd/adapters.py +54 -0
  19. neuralosd-1.0.0/src/neuralosd/backends/__init__.py +15 -0
  20. neuralosd-1.0.0/src/neuralosd/backends/boxlite_backend.py +69 -0
  21. neuralosd-1.0.0/src/neuralosd/backends/msb_backend.py +58 -0
  22. neuralosd-1.0.0/src/neuralosd/chains.py +97 -0
  23. neuralosd-1.0.0/src/neuralosd/cli.py +147 -0
  24. neuralosd-1.0.0/src/neuralosd/engine.py +82 -0
  25. neuralosd-1.0.0/src/neuralosd/hitl.py +46 -0
  26. neuralosd-1.0.0/src/neuralosd/instance.py +99 -0
  27. neuralosd-1.0.0/src/neuralosd/lint.py +46 -0
  28. neuralosd-1.0.0/src/neuralosd/mcp.py +99 -0
  29. neuralosd-1.0.0/src/neuralosd/memory.py +51 -0
  30. neuralosd-1.0.0/src/neuralosd/meta.py +57 -0
  31. neuralosd-1.0.0/src/neuralosd/metrics.py +27 -0
  32. neuralosd-1.0.0/src/neuralosd/probe.py +74 -0
  33. neuralosd-1.0.0/src/neuralosd/registry.py +44 -0
  34. neuralosd-1.0.0/src/neuralosd/router.py +376 -0
  35. neuralosd-1.0.0/src/neuralosd/scheduler.py +86 -0
  36. neuralosd-1.0.0/src/neuralosd/service.py +57 -0
  37. neuralosd-1.0.0/src/neuralosd.egg-info/PKG-INFO +151 -0
  38. neuralosd-1.0.0/src/neuralosd.egg-info/SOURCES.txt +45 -0
  39. neuralosd-1.0.0/src/neuralosd.egg-info/dependency_links.txt +1 -0
  40. neuralosd-1.0.0/src/neuralosd.egg-info/entry_points.txt +2 -0
  41. neuralosd-1.0.0/src/neuralosd.egg-info/requires.txt +22 -0
  42. neuralosd-1.0.0/src/neuralosd.egg-info/top_level.txt +1 -0
  43. neuralosd-1.0.0/tests/test_backends.py +23 -0
  44. neuralosd-1.0.0/tests/test_framework.py +134 -0
  45. neuralosd-1.0.0/tests/test_integration.py +109 -0
  46. neuralosd-1.0.0/tests/test_probe.py +76 -0
  47. neuralosd-1.0.0/tests/test_router.py +97 -0
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: neuralosd
3
+ Version: 1.0.0
4
+ Summary: Deterministic-first agentic runtime — @probe framework, chain runner, meta-selector, HITL guardrails, MCP/OpenAPI exposure, and microVM sandbox backends (BoxLite / Microsandbox)
5
+ Author-email: Hyperspace Technologies <agent@superagent.ng>
6
+ License: MIT
7
+ Keywords: neuralos,agentic,sandbox,microvm,on-device,tool-calling,deterministic,offline,probes
8
+ Classifier: Development Status :: 5 - Production/Stable
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: MacOS
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Provides-Extra: model
22
+ Requires-Dist: neuralos>=3.0.3; extra == "model"
23
+ Provides-Extra: boxlite
24
+ Requires-Dist: boxlite>=0.10.0; extra == "boxlite"
25
+ Provides-Extra: msb
26
+ Provides-Extra: data
27
+ Requires-Dist: pydantic>=2; extra == "data"
28
+ Requires-Dist: pymysql; extra == "data"
29
+ Provides-Extra: all
30
+ Requires-Dist: neuralos>=3.0.3; extra == "all"
31
+ Requires-Dist: boxlite>=0.10.0; extra == "all"
32
+ Requires-Dist: pydantic>=2; extra == "all"
33
+ Requires-Dist: pymysql; extra == "all"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest; extra == "dev"
36
+ Requires-Dist: pytest-asyncio; extra == "dev"
37
+
38
+ # neuralosd — deterministic-first agentic runtime
39
+
40
+ **One pip install. Two sandbox backends. Any data source. Offline. On CPU.**
41
+
42
+ `neuralosd` is the agentic runtime for [neuralOS](https://neuralos.ng) — the
43
+ 121M-parameter on-device tool-calling model. It turns any data source into a
44
+ private, offline question-answering service inside hardware-isolated microVMs.
45
+
46
+ ```
47
+ pip install neuralosd[all]
48
+ ```
49
+
50
+ ## What it does
51
+
52
+ ```
53
+ YOUR DATA (CSV, DB, API, logs) THE RUNTIME THE RESULT
54
+ ────────────────────── ────────────── ──────────────
55
+ profile → model → generate → @probe + router → ask in English,
56
+ → chains + guardrails get verified
57
+ → serve + monitor answers, offline
58
+ ```
59
+
60
+ ## Two sandbox backends
61
+
62
+ | Backend | Install | Best for |
63
+ |---|---|---|
64
+ | **BoxLite** | `pip install neuralosd[boxlite]` | persistent service boxes, CoW clones, port publication |
65
+ | **Microsandbox** | `pip install neuralosd[msb]` | live RAM snapshots, CoW forks, declarative recreate |
66
+
67
+ Both run the same probe contract. Switch by configuration, not code.
68
+
69
+ ## Quick start
70
+
71
+ ```bash
72
+ # 1. Install
73
+ pip install neuralosd[all]
74
+
75
+ # 2. Build an instance from your data
76
+ neuralosd build --source your_data.csv --name my-analyst
77
+
78
+ # 3. Deploy into a sandbox
79
+ neuralosd deploy --name my-analyst --backend boxlite
80
+
81
+ # 4. Ask
82
+ neuralosd ask --instance my-analyst "how many records"
83
+ ```
84
+
85
+ ## The @probe framework
86
+
87
+ ```python
88
+ from neuralosd import probe, Instance
89
+
90
+ @probe(
91
+ description="Customers ranked by lifetime spend",
92
+ triggers=["top customers", "best customers"],
93
+ args={"limit": {"type": "integer", "min": 1, "max": 25, "default": 10}},
94
+ pii=["email"],
95
+ )
96
+ def top_customers(limit: int = 10):
97
+ return db.query("SELECT ... LIMIT %s", (limit,))
98
+
99
+ inst = Instance(name="my-analyst", probes=[top_customers])
100
+ env = inst.ask("top customers")
101
+ print(env["results"])
102
+ ```
103
+
104
+ ## Chains (multi-step answers)
105
+
106
+ ```python
107
+ from neuralosd import chain, ChainRunner
108
+
109
+ @chain(name="genre_deep_dive", steps=[
110
+ {"probe": "top_genres"},
111
+ {"probe": "tracks_by_genre", "args": {"genre": "{{step_0.genre}}"}},
112
+ ])
113
+ def genre_deep_dive(ctx): ...
114
+
115
+ runner = ChainRunner(probes_by_name)
116
+ runner.register("genre_deep_dive", genre_deep_dive._chain_steps)
117
+ result = runner.run("genre_deep_dive")
118
+ ```
119
+
120
+ ## Meta-selector (multi-instance routing)
121
+
122
+ ```python
123
+ from neuralosd import MetaSelector
124
+
125
+ selector = MetaSelector({
126
+ "finance": {"description": "revenue, invoices, customers"},
127
+ "ops": {"description": "incidents, uptime, alerts"},
128
+ })
129
+ instance = selector.route("how many open incidents") # → "ops"
130
+ ```
131
+
132
+ ## HITL guardrails
133
+
134
+ ```python
135
+ from neuralosd import ConfirmStore
136
+ store = ConfirmStore()
137
+ pending = store.create(probe_fn, args, reason="low confidence")
138
+ # ... human confirms ...
139
+ result = store.confirm(pending["confirm_token"])
140
+ ```
141
+
142
+ ## MCP server (expose probes to any AI agent)
143
+
144
+ ```bash
145
+ python3 -m neuralosd.mcp /path/to/instance
146
+ # or add to Claude Desktop / Cursor MCP config
147
+ ```
148
+
149
+ ## License
150
+
151
+ MIT
@@ -0,0 +1,114 @@
1
+ # neuralosd — deterministic-first agentic runtime
2
+
3
+ **One pip install. Two sandbox backends. Any data source. Offline. On CPU.**
4
+
5
+ `neuralosd` is the agentic runtime for [neuralOS](https://neuralos.ng) — the
6
+ 121M-parameter on-device tool-calling model. It turns any data source into a
7
+ private, offline question-answering service inside hardware-isolated microVMs.
8
+
9
+ ```
10
+ pip install neuralosd[all]
11
+ ```
12
+
13
+ ## What it does
14
+
15
+ ```
16
+ YOUR DATA (CSV, DB, API, logs) THE RUNTIME THE RESULT
17
+ ────────────────────── ────────────── ──────────────
18
+ profile → model → generate → @probe + router → ask in English,
19
+ → chains + guardrails get verified
20
+ → serve + monitor answers, offline
21
+ ```
22
+
23
+ ## Two sandbox backends
24
+
25
+ | Backend | Install | Best for |
26
+ |---|---|---|
27
+ | **BoxLite** | `pip install neuralosd[boxlite]` | persistent service boxes, CoW clones, port publication |
28
+ | **Microsandbox** | `pip install neuralosd[msb]` | live RAM snapshots, CoW forks, declarative recreate |
29
+
30
+ Both run the same probe contract. Switch by configuration, not code.
31
+
32
+ ## Quick start
33
+
34
+ ```bash
35
+ # 1. Install
36
+ pip install neuralosd[all]
37
+
38
+ # 2. Build an instance from your data
39
+ neuralosd build --source your_data.csv --name my-analyst
40
+
41
+ # 3. Deploy into a sandbox
42
+ neuralosd deploy --name my-analyst --backend boxlite
43
+
44
+ # 4. Ask
45
+ neuralosd ask --instance my-analyst "how many records"
46
+ ```
47
+
48
+ ## The @probe framework
49
+
50
+ ```python
51
+ from neuralosd import probe, Instance
52
+
53
+ @probe(
54
+ description="Customers ranked by lifetime spend",
55
+ triggers=["top customers", "best customers"],
56
+ args={"limit": {"type": "integer", "min": 1, "max": 25, "default": 10}},
57
+ pii=["email"],
58
+ )
59
+ def top_customers(limit: int = 10):
60
+ return db.query("SELECT ... LIMIT %s", (limit,))
61
+
62
+ inst = Instance(name="my-analyst", probes=[top_customers])
63
+ env = inst.ask("top customers")
64
+ print(env["results"])
65
+ ```
66
+
67
+ ## Chains (multi-step answers)
68
+
69
+ ```python
70
+ from neuralosd import chain, ChainRunner
71
+
72
+ @chain(name="genre_deep_dive", steps=[
73
+ {"probe": "top_genres"},
74
+ {"probe": "tracks_by_genre", "args": {"genre": "{{step_0.genre}}"}},
75
+ ])
76
+ def genre_deep_dive(ctx): ...
77
+
78
+ runner = ChainRunner(probes_by_name)
79
+ runner.register("genre_deep_dive", genre_deep_dive._chain_steps)
80
+ result = runner.run("genre_deep_dive")
81
+ ```
82
+
83
+ ## Meta-selector (multi-instance routing)
84
+
85
+ ```python
86
+ from neuralosd import MetaSelector
87
+
88
+ selector = MetaSelector({
89
+ "finance": {"description": "revenue, invoices, customers"},
90
+ "ops": {"description": "incidents, uptime, alerts"},
91
+ })
92
+ instance = selector.route("how many open incidents") # → "ops"
93
+ ```
94
+
95
+ ## HITL guardrails
96
+
97
+ ```python
98
+ from neuralosd import ConfirmStore
99
+ store = ConfirmStore()
100
+ pending = store.create(probe_fn, args, reason="low confidence")
101
+ # ... human confirms ...
102
+ result = store.confirm(pending["confirm_token"])
103
+ ```
104
+
105
+ ## MCP server (expose probes to any AI agent)
106
+
107
+ ```bash
108
+ python3 -m neuralosd.mcp /path/to/instance
109
+ # or add to Claude Desktop / Cursor MCP config
110
+ ```
111
+
112
+ ## License
113
+
114
+ MIT
@@ -0,0 +1,44 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "neuralosd"
7
+ version = "1.0.0"
8
+ description = "Deterministic-first agentic runtime — @probe framework, chain runner, meta-selector, HITL guardrails, MCP/OpenAPI exposure, and microVM sandbox backends (BoxLite / Microsandbox)"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Hyperspace Technologies", email = "agent@superagent.ng" }]
13
+ keywords = ["neuralos", "agentic", "sandbox", "microvm", "on-device",
14
+ "tool-calling", "deterministic", "offline", "probes"]
15
+ classifiers = [
16
+ "Development Status :: 5 - Production/Stable",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: MIT License",
19
+ "Operating System :: MacOS",
20
+ "Operating System :: POSIX :: Linux",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Topic :: Software Development :: Libraries :: Python Modules",
26
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
27
+ ]
28
+
29
+ [project.scripts]
30
+ neuralosd = "neuralosd.cli:main"
31
+
32
+ [project.optional-dependencies]
33
+ model = ["neuralos>=3.0.3"]
34
+ boxlite = ["boxlite>=0.10.0"]
35
+ msb = []
36
+ data = ["pydantic>=2", "pymysql"]
37
+ all = ["neuralos>=3.0.3", "boxlite>=0.10.0", "pydantic>=2", "pymysql"]
38
+ dev = ["pytest", "pytest-asyncio"]
39
+
40
+ [tool.setuptools.packages.find]
41
+ where = ["src"]
42
+
43
+ [tool.pytest.ini_options]
44
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,24 @@
1
+ """neuralosd — deterministic-first agentic runtime for neuralOS.
2
+
3
+ One pip install. Two sandbox backends (BoxLite, Microsandbox). Any data
4
+ source. Offline. On CPU. With verification gates, audit trail, and
5
+ deterministic routing.
6
+ """
7
+ __version__ = "1.0.0"
8
+
9
+ from .probe import probe, enum_arg, pattern_arg, int_arg, ProbeMeta
10
+ from .router import Router, NoResults
11
+ from .instance import Instance
12
+ from .chains import ChainRunner, chain, ChainError
13
+ from .meta import MetaSelector
14
+ from .hitl import ConfirmStore, ConfirmRequired
15
+ from .lint import TriggerLinter
16
+
17
+ __all__ = [
18
+ "probe", "enum_arg", "pattern_arg", "int_arg", "ProbeMeta",
19
+ "Router", "NoResults", "Instance",
20
+ "ChainRunner", "chain", "ChainError",
21
+ "MetaSelector",
22
+ "ConfirmStore", "ConfirmRequired",
23
+ "TriggerLinter",
24
+ ]
File without changes
@@ -0,0 +1,7 @@
1
+ import os, sys, json
2
+ def run(a):
3
+ d = os.path.abspath(a.instance_dir)
4
+ os.chdir(d); sys.path.insert(0, d)
5
+ import ask
6
+ sys.argv = ["ask.py"] + [a.question] if hasattr(a, 'question') else sys.argv
7
+ ask.main() if hasattr(ask, 'main') else None
@@ -0,0 +1,13 @@
1
+ def run(a):
2
+ import sys, subprocess, os
3
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
4
+ "..", "tools", "calibrate.py")
5
+ if not os.path.exists(script):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
7
+ "..", "..", "..",
8
+ "agent-skills", "skills", "neuralos", "scripts",
9
+ "calibrate.py")
10
+ if os.path.exists(script):
11
+ raise SystemExit(subprocess.call([sys.executable, script] + sys.argv[1:]))
12
+ print(f"tool script not found: {script}")
13
+ raise SystemExit(1)
@@ -0,0 +1,13 @@
1
+ def run(a):
2
+ import sys, subprocess, os
3
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
4
+ "..", "tools", "diff.py")
5
+ if not os.path.exists(script):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
7
+ "..", "..", "..",
8
+ "agent-skills", "skills", "neuralos", "scripts",
9
+ "diff.py")
10
+ if os.path.exists(script):
11
+ raise SystemExit(subprocess.call([sys.executable, script] + sys.argv[1:]))
12
+ print(f"tool script not found: {script}")
13
+ raise SystemExit(1)
@@ -0,0 +1,13 @@
1
+ def run(a):
2
+ import sys, subprocess, os
3
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
4
+ "..", "tools", "gaps.py")
5
+ if not os.path.exists(script):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
7
+ "..", "..", "..",
8
+ "agent-skills", "skills", "neuralos", "scripts",
9
+ "gaps.py")
10
+ if os.path.exists(script):
11
+ raise SystemExit(subprocess.call([sys.executable, script] + sys.argv[1:]))
12
+ print(f"tool script not found: {script}")
13
+ raise SystemExit(1)
@@ -0,0 +1,13 @@
1
+ def run(a):
2
+ import sys, subprocess, os
3
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
4
+ "..", "tools", "golden.py")
5
+ if not os.path.exists(script):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
7
+ "..", "..", "..",
8
+ "agent-skills", "skills", "neuralos", "scripts",
9
+ "golden.py")
10
+ if os.path.exists(script):
11
+ raise SystemExit(subprocess.call([sys.executable, script] + sys.argv[1:]))
12
+ print(f"tool script not found: {script}")
13
+ raise SystemExit(1)
@@ -0,0 +1,21 @@
1
+ def run(a):
2
+ import subprocess, sys, os
3
+ out = a.out or f"./{a.name}"
4
+ scripts = os.path.join(os.path.dirname(os.path.abspath(__file__)),
5
+ "..", "..", "..", "..",
6
+ "agent-skills", "skills", "neuralos", "scripts")
7
+ profile = os.path.join(out, "profile.json")
8
+ os.makedirs(out, exist_ok=True)
9
+ for step in [
10
+ [sys.executable, os.path.join(scripts, "profile_data.py"),
11
+ "--source", a.source, "--out", profile],
12
+ [sys.executable, os.path.join(scripts, "gen_pydantic.py"),
13
+ "--profile", profile, "--out", os.path.join(out, "models.py")],
14
+ [sys.executable, os.path.join(scripts, "gen_needle_instance.py"),
15
+ "--profile", profile, "--models", os.path.join(out, "models.py"),
16
+ "--out", out, "--agent-name", a.name],
17
+ ]:
18
+ r = subprocess.run(step, capture_output=True, text=True)
19
+ if r.returncode:
20
+ print(r.stderr[-500:]); raise SystemExit(r.returncode)
21
+ print(f"instance '{a.name}' generated at {out}")
@@ -0,0 +1,13 @@
1
+ def run(a):
2
+ import sys, subprocess, os
3
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
4
+ "..", "tools", "invariants.py")
5
+ if not os.path.exists(script):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
7
+ "..", "..", "..",
8
+ "agent-skills", "skills", "neuralos", "scripts",
9
+ "invariants.py")
10
+ if os.path.exists(script):
11
+ raise SystemExit(subprocess.call([sys.executable, script] + sys.argv[1:]))
12
+ print(f"tool script not found: {script}")
13
+ raise SystemExit(1)
@@ -0,0 +1,8 @@
1
+ import json, sys
2
+ def run(a):
3
+ from neuralosd.lint import TriggerLinter
4
+ menu = json.load(open(a.menu))
5
+ r = TriggerLinter(menu, top=a.top).lint()
6
+ for h in r["hard"]: print(f"HARD {h}")
7
+ for s in r["soft"]: print(f"soft {s}")
8
+ raise SystemExit(1 if r["hard"] else 0)
@@ -0,0 +1,13 @@
1
+ def run(a):
2
+ import sys, subprocess, os
3
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
4
+ "..", "tools", "openapi.py")
5
+ if not os.path.exists(script):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
7
+ "..", "..", "..",
8
+ "agent-skills", "skills", "neuralos", "scripts",
9
+ "openapi.py")
10
+ if os.path.exists(script):
11
+ raise SystemExit(subprocess.call([sys.executable, script] + sys.argv[1:]))
12
+ print(f"tool script not found: {script}")
13
+ raise SystemExit(1)
@@ -0,0 +1,5 @@
1
+ import os, sys
2
+ def run(a):
3
+ d = os.path.abspath(a.instance_dir)
4
+ os.chdir(d); sys.path.insert(0, d)
5
+ import serve; serve.main()
@@ -0,0 +1,13 @@
1
+ def run(a):
2
+ import sys, subprocess, os
3
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
4
+ "..", "tools", "truth.py")
5
+ if not os.path.exists(script):
6
+ script = os.path.join(os.path.dirname(os.path.abspath(__file__)),
7
+ "..", "..", "..",
8
+ "agent-skills", "skills", "neuralos", "scripts",
9
+ "truth.py")
10
+ if os.path.exists(script):
11
+ raise SystemExit(subprocess.call([sys.executable, script] + sys.argv[1:]))
12
+ print(f"tool script not found: {script}")
13
+ raise SystemExit(1)
@@ -0,0 +1,54 @@
1
+ """Sandbox adapters — route probe execution to BoxLite / MSB sandboxes.
2
+
3
+ An adapter implements the same interface as an in-process probe: takes
4
+ kwargs, returns a result dict. The instance's tier declaration routes
5
+ execution to the right substrate.
6
+ """
7
+ import json
8
+ import urllib.request
9
+ from typing import Any, Dict
10
+
11
+
12
+ class BoxLiteAdapter:
13
+ """Executes probes inside a BoxLite box via `boxlite serve` REST."""
14
+
15
+ def __init__(self, serve_url: str = "http://localhost:8100",
16
+ api_key: str = None, box_name: str = "chinook-1gb"):
17
+ self.serve_url = serve_url.rstrip("/")
18
+ self.api_key = api_key
19
+ self.box_name = box_name
20
+
21
+ def exec_probe(self, code: str) -> Dict:
22
+ """Run a Python snippet inside the sandbox."""
23
+ req = urllib.request.Request(
24
+ f"{self.serve_url}/v1/boxes/{self.box_name}/exec",
25
+ data=json.dumps({"command": code}).encode(),
26
+ headers={"Content-Type": "application/json",
27
+ **({"Authorization": f"Bearer {self.api_key}"}
28
+ if self.api_key else {})})
29
+ r = urllib.request.urlopen(req, timeout=120)
30
+ return json.loads(r.read())
31
+
32
+
33
+ class MSBAdapter:
34
+ """Executes probes inside a Microsandbox via `msb exec`."""
35
+
36
+ def __init__(self, sandbox_name: str = "chinook-ms"):
37
+ self.sandbox_name = sandbox_name
38
+
39
+ def exec_probe(self, code: str) -> Dict:
40
+ import subprocess
41
+ r = subprocess.run(
42
+ ["msb", "exec", self.sandbox_name, "--", "python3", "-c", code],
43
+ capture_output=True, text=True, timeout=120)
44
+ return {"stdout": r.stdout, "stderr": r.stderr,
45
+ "exit_code": r.returncode}
46
+
47
+
48
+ def get_adapter(tier: str, **kwargs) -> Any:
49
+ """Factory: tier string → adapter instance, or None for in-process."""
50
+ if tier.startswith("sandbox:boxlite:"):
51
+ return BoxLiteAdapter(box_name=tier.split(":")[-1], **kwargs)
52
+ if tier.startswith("sandbox:msb:"):
53
+ return MSBAdapter(sandbox_name=tier.split(":")[-1], **kwargs)
54
+ return None # in-process
@@ -0,0 +1,15 @@
1
+ from .boxlite_backend import BoxLiteBackend
2
+ from .msb_backend import MSBBackend
3
+
4
+
5
+ def get_backend(name: str, **kwargs):
6
+ if name == "boxlite":
7
+ return BoxLiteBackend(**kwargs)
8
+ if name == "msb":
9
+ return MSBBackend(**kwargs)
10
+ raise ValueError(f"unknown backend: {name}")
11
+
12
+
13
+ def available_backends():
14
+ return {"boxlite": BoxLiteBackend.available(),
15
+ "msb": MSBBackend.available()}
@@ -0,0 +1,69 @@
1
+ """BoxLite backend — lifecycle management for BoxLite microVM boxes."""
2
+ import asyncio
3
+ from typing import Any, Dict, Optional
4
+
5
+
6
+ class BoxLiteBackend:
7
+ """Manages BoxLite box lifecycle for neuralOS instances."""
8
+
9
+ def __init__(self, serve_url: str = None, api_key: str = None):
10
+ self.serve_url = serve_url
11
+ self.api_key = api_key
12
+
13
+ def _rt(self):
14
+ import boxlite
15
+ if self.serve_url:
16
+ cred = boxlite.ApiKeyCredential(self.api_key) if self.api_key else None
17
+ return boxlite.Boxlite.rest(
18
+ boxlite.BoxliteRestOptions(url=self.serve_url, credential=cred))
19
+ return boxlite.Boxlite.default()
20
+
21
+ async def create(self, name: str, image: str = "python:3.12-slim",
22
+ cpus: int = 1, memory_mib: int = 1024,
23
+ disk_gb: int = 6, **kwargs):
24
+ rt = self._rt()
25
+ got = await rt.get_or_create(
26
+ boxlite.BoxOptions(image=image, auto_delete=0,
27
+ cpus=cpus, memory_mib=memory_mib,
28
+ disk_size_gb=disk_gb, **kwargs),
29
+ name=name)
30
+ return got[0] if isinstance(got, tuple) else got
31
+
32
+ async def start(self, name: str):
33
+ box = await self._rt().get(name)
34
+ await box.start()
35
+
36
+ async def stop(self, name: str):
37
+ box = await self._rt().get(name)
38
+ await box.stop()
39
+
40
+ async def remove(self, name: str):
41
+ await self._rt().remove(name)
42
+
43
+ async def fork(self, template: str, name: str):
44
+ tpl = await self._rt().get(template)
45
+ return await tpl.clone_box(name=name)
46
+
47
+ async def exec(self, name: str, cmd: str, args: list = None):
48
+ box = await self._rt().get(name)
49
+ ex = await box.exec(cmd, args or [], timeout_secs=300)
50
+ out = []
51
+ async for line in ex.stdout(): out.append(line)
52
+ await ex.wait()
53
+ return "".join(out)
54
+
55
+ async def export(self, name: str, dest: str):
56
+ box = await self._rt().get(name)
57
+ await box.export(dest=dest)
58
+
59
+ @staticmethod
60
+ def available() -> bool:
61
+ try:
62
+ import boxlite
63
+ return True
64
+ except ImportError:
65
+ return False
66
+
67
+ @staticmethod
68
+ def name() -> str:
69
+ return "boxlite"