AbteeXAILabs commited on
Commit
dc6ccfd
·
verified ·
1 Parent(s): fc2f507

Publish expanded LumynaX product platform package

Browse files
MANIFEST.in ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ include README.md LICENSE requirements.txt SMOKE_TESTS.md PYPI_RELEASE.md quickstart.py product_manifest.json product_blueprint.md architecture.md
2
+ recursive-include sovereigncode *.py py.typed
3
+ recursive-include sovereigncode/configs *
4
+ recursive-include sovereigncode/examples *
5
+ recursive-include sovereigncode/integrations *
6
+ recursive-include sovereigncode/policy-packs *
7
+ recursive-include sovereigncode/schemas *
8
+ recursive-include marama_route *.py py.typed
9
+ recursive-include marama_route/configs *
10
+ recursive-include marama_route/examples *
11
+ recursive-include marama_route/integrations *
12
+ recursive-include marama_route/schemas *
PYPI_RELEASE.md ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # PyPI Release: AbteeX SovereignCode
2
+
3
+ Package: `abteex-sovereigncode`
4
+ Version: `0.4.0`
5
+
6
+ ## Local Build
7
+
8
+ ```bash
9
+ python -m build
10
+ python -m twine check dist/*
11
+ python quickstart.py
12
+ sovereigncode serve --smoke
13
+ ```
14
+
15
+ ## Publish
16
+
17
+ ```bash
18
+ python -m twine upload dist/*
19
+ ```
20
+
21
+ Required local credentials: `TWINE_USERNAME=__token__` and `TWINE_PASSWORD=<pypi-token>`.
22
+ The GitHub workflow can publish with PyPI trusted publishing when the PyPI project
23
+ is configured to trust `Aimaghsoodi/TinyLuminaX`.
24
+
25
+ ## Runtime Surface
26
+
27
+ - CLI: `sovereigncode`
28
+ - Local UI/API: `sovereigncode serve --port 8788 --open`
29
+ - Policy API: `POST /v1/evaluate`, `POST /v1/plan-turn`, `POST /v1/tool-check`
30
+ - Audit: `GET /v1/audit` and `sovereigncode audit --limit 25`
README.md CHANGED
@@ -21,10 +21,17 @@ language:
21
  # AbteeX SovereignCode
22
  <!-- abteex-sovereigncode-card:v3 -->
23
 
24
- Standalone release package for `AbteeXAILab/sovereigncode`.
25
 
26
  ## Install
27
 
 
 
 
 
 
 
 
28
  ```bash
29
  hf download AbteeXAILab/sovereigncode --local-dir sovereigncode --repo-type model
30
  cd sovereigncode
@@ -35,6 +42,10 @@ python quickstart.py
35
  ## Included Runtime Commands
36
 
37
  ```bash
 
 
 
 
38
  python -m sovereigncode.cli evaluate --capsule examples/capsule.restricted-nz-code.json --request examples/request.allowed-local-edit.json
39
  python -m sovereigncode.cli plan-turn --capsule examples/capsule.restricted-nz-code.json --request examples/request.allowed-local-edit.json --route-request examples/request.code-restricted.json --registry configs/lumynax_model_registry.json
40
  python -m sovereigncode.cli policy-matrix --capsule examples/capsule.restricted-nz-code.json --request examples/request.allowed-local-edit.json
@@ -83,6 +94,16 @@ The initial product scaffold includes:
83
 
84
  ## Quickstart
85
 
 
 
 
 
 
 
 
 
 
 
86
  From the repo root:
87
 
88
  ```bash
@@ -162,6 +183,16 @@ py -3 -m tinyluminax.products.sovereigncode.cli audit --limit 10
162
 
163
  The service exposes `GET /health`, `GET /v1/audit`, `POST /v1/evaluate`, `POST /v1/plan-turn`, `POST /v1/tool-check`, `POST /v1/policy-matrix`, and the existing browser `/api/*` routes. It writes JSONL audit records to `.sovereigncode/audit.jsonl` by default.
164
 
 
 
 
 
 
 
 
 
 
 
165
  Smoke-check the UI routes without opening a browser:
166
 
167
  ```bash
 
21
  # AbteeX SovereignCode
22
  <!-- abteex-sovereigncode-card:v3 -->
23
 
24
+ Standalone release package for PyPI package `abteex-sovereigncode` and Hugging Face repo `AbteeXAILab/sovereigncode`.
25
 
26
  ## Install
27
 
28
+ ```bash
29
+ pip install abteex-sovereigncode
30
+ sovereigncode serve --smoke
31
+ ```
32
+
33
+ HF mirror install:
34
+
35
  ```bash
36
  hf download AbteeXAILab/sovereigncode --local-dir sovereigncode --repo-type model
37
  cd sovereigncode
 
42
  ## Included Runtime Commands
43
 
44
  ```bash
45
+ sovereigncode serve --smoke
46
+ sovereigncode audit --limit 5
47
+ sovereigncode opencode-config
48
+ sovereigncode ui --port 8788 --open
49
  python -m sovereigncode.cli evaluate --capsule examples/capsule.restricted-nz-code.json --request examples/request.allowed-local-edit.json
50
  python -m sovereigncode.cli plan-turn --capsule examples/capsule.restricted-nz-code.json --request examples/request.allowed-local-edit.json --route-request examples/request.code-restricted.json --registry configs/lumynax_model_registry.json
51
  python -m sovereigncode.cli policy-matrix --capsule examples/capsule.restricted-nz-code.json --request examples/request.allowed-local-edit.json
 
94
 
95
  ## Quickstart
96
 
97
+ Install the standalone package:
98
+
99
+ ```bash
100
+ pip install abteex-sovereigncode
101
+ sovereigncode serve --smoke
102
+ sovereigncode serve --port 8788 --open
103
+ ```
104
+
105
+ The same package is mirrored on Hugging Face at `AbteeXAILab/sovereigncode` and can be installed from a downloaded snapshot with `pip install -e .`.
106
+
107
  From the repo root:
108
 
109
  ```bash
 
183
 
184
  The service exposes `GET /health`, `GET /v1/audit`, `POST /v1/evaluate`, `POST /v1/plan-turn`, `POST /v1/tool-check`, `POST /v1/policy-matrix`, and the existing browser `/api/*` routes. It writes JSONL audit records to `.sovereigncode/audit.jsonl` by default.
185
 
186
+ ## PyPI Release Readiness
187
+
188
+ The generated standalone package includes `pyproject.toml`, `MANIFEST.in`, `SMOKE_TESTS.md`, `PYPI_RELEASE.md`, package data, console script entry points, and wheel/sdist validation support. The release gate is:
189
+
190
+ ```bash
191
+ py -3 scripts/build_product_release_packages.py
192
+ py -3 scripts/verify_product_installs.py --product sovereigncode
193
+ py -3 scripts/publish_products_to_pypi.py --product sovereigncode --dry-run
194
+ ```
195
+
196
  Smoke-check the UI routes without opening a browser:
197
 
198
  ```bash
configs/gateway.local.json CHANGED
@@ -1,13 +1,13 @@
1
- {
2
- "mode": "route_only",
3
- "prompt_retention": "not_stored_by_default",
4
- "default_timeout_seconds": 120,
5
- "backends": {
6
- "example-local-openai-compatible": {
7
- "type": "openai_compatible",
8
- "base_url": "http://127.0.0.1:8000/v1",
9
- "api_key_env": "",
10
- "model": "local-model-id"
11
- }
12
- }
13
- }
 
1
+ {
2
+ "mode": "route_only",
3
+ "prompt_retention": "not_stored_by_default",
4
+ "default_timeout_seconds": 120,
5
+ "backends": {
6
+ "example-local-openai-compatible": {
7
+ "type": "openai_compatible",
8
+ "base_url": "http://127.0.0.1:8000/v1",
9
+ "api_key_env": "",
10
+ "model": "local-model-id"
11
+ }
12
+ }
13
+ }
configs/service.local.json CHANGED
@@ -1,14 +1,14 @@
1
- {
2
- "ledger_path": ".sovereigncode/audit.jsonl",
3
- "default_region": "NZ",
4
- "fail_closed": true,
5
- "require_human_review_for": [
6
- "write_files",
7
- "execute_shell",
8
- "network_export",
9
- "commit",
10
- "publish",
11
- "train_model"
12
- ],
13
- "marama_route_base_url": "http://127.0.0.1:8787/v1"
14
- }
 
1
+ {
2
+ "ledger_path": ".sovereigncode/audit.jsonl",
3
+ "default_region": "NZ",
4
+ "fail_closed": true,
5
+ "require_human_review_for": [
6
+ "write_files",
7
+ "execute_shell",
8
+ "network_export",
9
+ "commit",
10
+ "publish",
11
+ "train_model"
12
+ ],
13
+ "marama_route_base_url": "http://127.0.0.1:8787/v1"
14
+ }
marama_route/__init__.py CHANGED
@@ -1,40 +1,40 @@
1
- from __future__ import annotations
2
-
3
- from .gateway import (
4
- build_chat_route_response,
5
- build_models_response,
6
- route_chat_payload,
7
- routing_request_from_chat_payload,
8
- )
9
- from .platform import (
10
- build_opencode_provider_config,
11
- build_registry_analytics,
12
- catalog_models,
13
- compare_models,
14
- route_scenario_matrix,
15
- )
16
- from .registry import ModelEndpoint, RoutingRequest, load_model_registry
17
- from .router import RouteDecision, SovereignModelRouter
18
- from .server import handle_gateway_request, load_gateway_config, smoke_gateway
19
- from .ui import smoke_ui as smoke_ui
20
-
21
- __all__ = [
22
- "ModelEndpoint",
23
- "RouteDecision",
24
- "RoutingRequest",
25
- "SovereignModelRouter",
26
- "build_chat_route_response",
27
- "build_models_response",
28
- "build_opencode_provider_config",
29
- "build_registry_analytics",
30
- "catalog_models",
31
- "compare_models",
32
- "handle_gateway_request",
33
- "load_gateway_config",
34
- "load_model_registry",
35
- "route_chat_payload",
36
- "route_scenario_matrix",
37
- "routing_request_from_chat_payload",
38
- "smoke_gateway",
39
- "smoke_ui",
40
- ]
 
1
+ from __future__ import annotations
2
+
3
+ from .gateway import (
4
+ build_chat_route_response,
5
+ build_models_response,
6
+ route_chat_payload,
7
+ routing_request_from_chat_payload,
8
+ )
9
+ from .platform import (
10
+ build_opencode_provider_config,
11
+ build_registry_analytics,
12
+ catalog_models,
13
+ compare_models,
14
+ route_scenario_matrix,
15
+ )
16
+ from .registry import ModelEndpoint, RoutingRequest, load_model_registry
17
+ from .router import RouteDecision, SovereignModelRouter
18
+ from .server import handle_gateway_request, load_gateway_config, smoke_gateway
19
+ from .ui import smoke_ui as smoke_ui
20
+
21
+ __all__ = [
22
+ "ModelEndpoint",
23
+ "RouteDecision",
24
+ "RoutingRequest",
25
+ "SovereignModelRouter",
26
+ "build_chat_route_response",
27
+ "build_models_response",
28
+ "build_opencode_provider_config",
29
+ "build_registry_analytics",
30
+ "catalog_models",
31
+ "compare_models",
32
+ "handle_gateway_request",
33
+ "load_gateway_config",
34
+ "load_model_registry",
35
+ "route_chat_payload",
36
+ "route_scenario_matrix",
37
+ "routing_request_from_chat_payload",
38
+ "smoke_gateway",
39
+ "smoke_ui",
40
+ ]
marama_route/_ui_server.py CHANGED
@@ -1,121 +1,121 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import socket
5
- import webbrowser
6
- from collections.abc import Callable
7
- from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
8
- from typing import Any
9
- from urllib.parse import urlparse
10
-
11
- ApiHandler = Callable[[str, str, dict[str, Any] | None], tuple[int, dict[str, Any]]]
12
-
13
-
14
- def find_available_port(host: str, preferred_port: int, *, attempts: int = 50) -> int:
15
- start = preferred_port if preferred_port > 0 else 0
16
- if start == 0:
17
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
18
- probe.bind((host, 0))
19
- return int(probe.getsockname()[1])
20
-
21
- for port in range(start, start + attempts):
22
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
23
- probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
24
- try:
25
- probe.bind((host, port))
26
- except OSError:
27
- continue
28
- return port
29
- raise OSError(f"No available port found from {preferred_port} to {preferred_port + attempts - 1}")
30
-
31
-
32
- def serve_dashboard(
33
- *,
34
- product_name: str,
35
- html: str,
36
- api_handler: ApiHandler,
37
- host: str,
38
- port: int,
39
- open_browser: bool = False,
40
- api_path_prefixes: tuple[str, ...] = ("/api/",),
41
- api_exact_paths: tuple[str, ...] = (),
42
- ) -> int:
43
- actual_port = find_available_port(host, port)
44
- exact_paths = set(api_exact_paths)
45
-
46
- def is_api_path(path: str) -> bool:
47
- return path in exact_paths or any(path.startswith(prefix) for prefix in api_path_prefixes)
48
-
49
- class Handler(BaseHTTPRequestHandler):
50
- server_version = "AbteeXProductUI/0.1"
51
-
52
- def do_GET(self) -> None: # noqa: N802 - stdlib handler method name
53
- path = urlparse(self.path).path
54
- if path == "/":
55
- self._send_text(200, html, "text/html; charset=utf-8")
56
- return
57
- if is_api_path(path):
58
- self._send_api("GET", path, None)
59
- return
60
- self._send_json(404, {"ok": False, "error": "not_found"})
61
-
62
- def do_POST(self) -> None: # noqa: N802 - stdlib handler method name
63
- path = urlparse(self.path).path
64
- if not is_api_path(path):
65
- self._send_json(404, {"ok": False, "error": "not_found"})
66
- return
67
- try:
68
- length = int(self.headers.get("Content-Length", "0"))
69
- raw = self.rfile.read(length).decode("utf-8") if length else "{}"
70
- payload = json.loads(raw)
71
- if not isinstance(payload, dict):
72
- raise ValueError("JSON body must be an object")
73
- self._send_api("POST", path, payload)
74
- except Exception as exc: # defensive API boundary
75
- self._send_json(400, {"ok": False, "error": str(exc)})
76
-
77
- def log_message(self, format: str, *args: Any) -> None: # noqa: A002
78
- return
79
-
80
- def _send_api(
81
- self,
82
- method: str,
83
- path: str,
84
- payload: dict[str, Any] | None,
85
- ) -> None:
86
- try:
87
- status, response = api_handler(method, path, payload)
88
- except Exception as exc: # defensive API boundary
89
- status, response = 500, {"ok": False, "error": str(exc)}
90
- self._send_json(status, response)
91
-
92
- def _send_json(self, status: int, payload: dict[str, Any]) -> None:
93
- body = json.dumps(payload, indent=2, sort_keys=True).encode("utf-8")
94
- self.send_response(status)
95
- self.send_header("Content-Type", "application/json; charset=utf-8")
96
- self.send_header("Content-Length", str(len(body)))
97
- self.send_header("Cache-Control", "no-store")
98
- self.end_headers()
99
- self.wfile.write(body)
100
-
101
- def _send_text(self, status: int, body: str, content_type: str) -> None:
102
- encoded = body.encode("utf-8")
103
- self.send_response(status)
104
- self.send_header("Content-Type", content_type)
105
- self.send_header("Content-Length", str(len(encoded)))
106
- self.send_header("Cache-Control", "no-store")
107
- self.end_headers()
108
- self.wfile.write(encoded)
109
-
110
- server = ThreadingHTTPServer((host, actual_port), Handler)
111
- url = f"http://{host}:{actual_port}/"
112
- print(f"{product_name} UI listening on {url}")
113
- if open_browser:
114
- webbrowser.open(url)
115
- try:
116
- server.serve_forever()
117
- except KeyboardInterrupt:
118
- print(f"{product_name} UI stopped")
119
- finally:
120
- server.server_close()
121
- return 0
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import socket
5
+ import webbrowser
6
+ from collections.abc import Callable
7
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
8
+ from typing import Any
9
+ from urllib.parse import urlparse
10
+
11
+ ApiHandler = Callable[[str, str, dict[str, Any] | None], tuple[int, dict[str, Any]]]
12
+
13
+
14
+ def find_available_port(host: str, preferred_port: int, *, attempts: int = 50) -> int:
15
+ start = preferred_port if preferred_port > 0 else 0
16
+ if start == 0:
17
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
18
+ probe.bind((host, 0))
19
+ return int(probe.getsockname()[1])
20
+
21
+ for port in range(start, start + attempts):
22
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
23
+ probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
24
+ try:
25
+ probe.bind((host, port))
26
+ except OSError:
27
+ continue
28
+ return port
29
+ raise OSError(f"No available port found from {preferred_port} to {preferred_port + attempts - 1}")
30
+
31
+
32
+ def serve_dashboard(
33
+ *,
34
+ product_name: str,
35
+ html: str,
36
+ api_handler: ApiHandler,
37
+ host: str,
38
+ port: int,
39
+ open_browser: bool = False,
40
+ api_path_prefixes: tuple[str, ...] = ("/api/",),
41
+ api_exact_paths: tuple[str, ...] = (),
42
+ ) -> int:
43
+ actual_port = find_available_port(host, port)
44
+ exact_paths = set(api_exact_paths)
45
+
46
+ def is_api_path(path: str) -> bool:
47
+ return path in exact_paths or any(path.startswith(prefix) for prefix in api_path_prefixes)
48
+
49
+ class Handler(BaseHTTPRequestHandler):
50
+ server_version = "AbteeXProductUI/0.1"
51
+
52
+ def do_GET(self) -> None: # noqa: N802 - stdlib handler method name
53
+ path = urlparse(self.path).path
54
+ if path == "/":
55
+ self._send_text(200, html, "text/html; charset=utf-8")
56
+ return
57
+ if is_api_path(path):
58
+ self._send_api("GET", path, None)
59
+ return
60
+ self._send_json(404, {"ok": False, "error": "not_found"})
61
+
62
+ def do_POST(self) -> None: # noqa: N802 - stdlib handler method name
63
+ path = urlparse(self.path).path
64
+ if not is_api_path(path):
65
+ self._send_json(404, {"ok": False, "error": "not_found"})
66
+ return
67
+ try:
68
+ length = int(self.headers.get("Content-Length", "0"))
69
+ raw = self.rfile.read(length).decode("utf-8") if length else "{}"
70
+ payload = json.loads(raw)
71
+ if not isinstance(payload, dict):
72
+ raise ValueError("JSON body must be an object")
73
+ self._send_api("POST", path, payload)
74
+ except Exception as exc: # defensive API boundary
75
+ self._send_json(400, {"ok": False, "error": str(exc)})
76
+
77
+ def log_message(self, format: str, *args: Any) -> None: # noqa: A002
78
+ return
79
+
80
+ def _send_api(
81
+ self,
82
+ method: str,
83
+ path: str,
84
+ payload: dict[str, Any] | None,
85
+ ) -> None:
86
+ try:
87
+ status, response = api_handler(method, path, payload)
88
+ except Exception as exc: # defensive API boundary
89
+ status, response = 500, {"ok": False, "error": str(exc)}
90
+ self._send_json(status, response)
91
+
92
+ def _send_json(self, status: int, payload: dict[str, Any]) -> None:
93
+ body = json.dumps(payload, indent=2, sort_keys=True).encode("utf-8")
94
+ self.send_response(status)
95
+ self.send_header("Content-Type", "application/json; charset=utf-8")
96
+ self.send_header("Content-Length", str(len(body)))
97
+ self.send_header("Cache-Control", "no-store")
98
+ self.end_headers()
99
+ self.wfile.write(body)
100
+
101
+ def _send_text(self, status: int, body: str, content_type: str) -> None:
102
+ encoded = body.encode("utf-8")
103
+ self.send_response(status)
104
+ self.send_header("Content-Type", content_type)
105
+ self.send_header("Content-Length", str(len(encoded)))
106
+ self.send_header("Cache-Control", "no-store")
107
+ self.end_headers()
108
+ self.wfile.write(encoded)
109
+
110
+ server = ThreadingHTTPServer((host, actual_port), Handler)
111
+ url = f"http://{host}:{actual_port}/"
112
+ print(f"{product_name} UI listening on {url}")
113
+ if open_browser:
114
+ webbrowser.open(url)
115
+ try:
116
+ server.serve_forever()
117
+ except KeyboardInterrupt:
118
+ print(f"{product_name} UI stopped")
119
+ finally:
120
+ server.server_close()
121
+ return 0
marama_route/cli.py CHANGED
@@ -1,233 +1,233 @@
1
- from __future__ import annotations
2
-
3
- import argparse
4
- import json
5
- from collections.abc import Sequence
6
- from pathlib import Path
7
- from typing import Any
8
-
9
- from .gateway import build_models_response, route_chat_payload
10
- from .platform import (
11
- build_opencode_provider_config,
12
- build_registry_analytics,
13
- catalog_models,
14
- compare_models,
15
- route_scenario_matrix,
16
- )
17
- from .registry import RoutingRequest, load_model_registry
18
- from .router import SovereignModelRouter
19
-
20
-
21
- def _load_json_mapping(path: Path) -> dict[str, Any]:
22
- payload = json.loads(path.read_text(encoding="utf-8-sig"))
23
- if not isinstance(payload, dict):
24
- raise ValueError(f"Expected mapping in {path}")
25
- return payload
26
-
27
-
28
- def _route(args: argparse.Namespace) -> int:
29
- models = load_model_registry(args.registry)
30
- payload = _load_json_mapping(args.request)
31
- decision = SovereignModelRouter(models).route(RoutingRequest.from_payload(payload))
32
- print(json.dumps(decision.to_dict(), indent=2, sort_keys=True))
33
- return 0 if decision.selected_model is not None else 2
34
-
35
-
36
- def _models(args: argparse.Namespace) -> int:
37
- models = load_model_registry(args.registry)
38
- print(json.dumps(build_models_response(models), indent=2, sort_keys=True))
39
- return 0
40
-
41
-
42
- def _chat_dry_run(args: argparse.Namespace) -> int:
43
- models = load_model_registry(args.registry)
44
- payload = _load_json_mapping(args.request)
45
- result = route_chat_payload(payload, models)
46
- print(json.dumps(result, indent=2, sort_keys=True))
47
- selected = result["route_decision"]["selected_model"]
48
- return 0 if selected is not None else 2
49
-
50
-
51
- def _catalog(args: argparse.Namespace) -> int:
52
- models = load_model_registry(args.registry)
53
- result = catalog_models(
54
- models,
55
- {
56
- "search": args.search,
57
- "task_type": args.task,
58
- "runtime": args.runtime,
59
- "modality": args.modality,
60
- "jurisdiction": args.jurisdiction,
61
- "min_context_tokens": args.min_context_tokens,
62
- "requires_json": args.requires_json,
63
- "requires_tools": args.requires_tools,
64
- "requires_local": args.requires_local,
65
- "limit": args.limit,
66
- },
67
- )
68
- print(json.dumps(result, indent=2, sort_keys=True))
69
- return 0
70
-
71
-
72
- def _compare(args: argparse.Namespace) -> int:
73
- models = load_model_registry(args.registry)
74
- model_ids = [item.strip() for value in args.model for item in value.split(",") if item.strip()]
75
- request = _load_json_mapping(args.request) if args.request else None
76
- result = compare_models(models, model_ids, request)
77
- print(json.dumps(result, indent=2, sort_keys=True))
78
- return 0 if result["ok"] else 2
79
-
80
-
81
- def _matrix(args: argparse.Namespace) -> int:
82
- models = load_model_registry(args.registry)
83
- result = route_scenario_matrix(models)
84
- print(json.dumps(result, indent=2, sort_keys=True))
85
- return 0 if result["ok"] or args.allow_blocked_exit_zero else 2
86
-
87
-
88
- def _analytics(args: argparse.Namespace) -> int:
89
- print(json.dumps(build_registry_analytics(load_model_registry(args.registry)), indent=2, sort_keys=True))
90
- return 0
91
-
92
-
93
- def _opencode_config(args: argparse.Namespace) -> int:
94
- models = load_model_registry(args.registry)
95
- result = build_opencode_provider_config(models, base_url=args.base_url)
96
- print(json.dumps(result, indent=2, sort_keys=True))
97
- return 0
98
-
99
-
100
- def _ui(args: argparse.Namespace) -> int:
101
- from .ui import run_ui
102
-
103
- return run_ui(
104
- registry_path=args.registry,
105
- host=args.host,
106
- port=args.port,
107
- open_browser=args.open,
108
- smoke=args.smoke,
109
- )
110
-
111
-
112
- def _serve(args: argparse.Namespace) -> int:
113
- from .server import serve_gateway
114
-
115
- return serve_gateway(
116
- registry_path=args.registry,
117
- config_path=args.config,
118
- host=args.host,
119
- port=args.port,
120
- open_browser=args.open,
121
- smoke=args.smoke,
122
- )
123
-
124
-
125
- def build_parser() -> argparse.ArgumentParser:
126
- parser = argparse.ArgumentParser(
127
- prog="lumynax-marama-route",
128
- description="Route requests across LumynaX sovereign model releases.",
129
- )
130
- subparsers = parser.add_subparsers(dest="command")
131
- route = subparsers.add_parser("route", help="Select a LumynaX model for a request.")
132
- route.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
133
- route.add_argument("--request", type=Path, required=True, help="Routing request JSON.")
134
- route.set_defaults(handler=_route)
135
-
136
- models = subparsers.add_parser(
137
- "models",
138
- help="Emit an OpenAI-compatible /v1/models response.",
139
- )
140
- models.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
141
- models.set_defaults(handler=_models)
142
-
143
- chat = subparsers.add_parser(
144
- "chat-dry-run",
145
- help="Route an OpenAI-compatible chat request without invoking a backend.",
146
- )
147
- chat.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
148
- chat.add_argument("--request", type=Path, required=True, help="OpenAI chat request JSON.")
149
- chat.set_defaults(handler=_chat_dry_run)
150
-
151
- catalog = subparsers.add_parser(
152
- "catalog",
153
- help="Search and filter the MaramaRoute model catalog.",
154
- )
155
- catalog.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
156
- catalog.add_argument("--search", default="")
157
- catalog.add_argument("--task", default="")
158
- catalog.add_argument("--runtime", default="")
159
- catalog.add_argument("--modality", default="")
160
- catalog.add_argument("--jurisdiction", default="NZ")
161
- catalog.add_argument("--min-context-tokens", type=int, default=0)
162
- catalog.add_argument("--requires-json", action=argparse.BooleanOptionalAction, default=False)
163
- catalog.add_argument("--requires-tools", action=argparse.BooleanOptionalAction, default=False)
164
- catalog.add_argument("--requires-local", action=argparse.BooleanOptionalAction, default=False)
165
- catalog.add_argument("--limit", type=int, default=25)
166
- catalog.set_defaults(handler=_catalog)
167
-
168
- compare = subparsers.add_parser(
169
- "compare",
170
- help="Compare routed fit for selected model ids.",
171
- )
172
- compare.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
173
- compare.add_argument("--model", action="append", required=True, help="Model id, repeatable or comma-separated.")
174
- compare.add_argument("--request", type=Path, default=None, help="Optional routing request JSON.")
175
- compare.set_defaults(handler=_compare)
176
-
177
- matrix = subparsers.add_parser(
178
- "matrix",
179
- help="Run the built-in sovereign routing scenario matrix.",
180
- )
181
- matrix.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
182
- matrix.add_argument("--allow-blocked-exit-zero", action=argparse.BooleanOptionalAction, default=False)
183
- matrix.set_defaults(handler=_matrix)
184
-
185
- analytics = subparsers.add_parser("analytics", help="Summarise registry coverage.")
186
- analytics.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
187
- analytics.set_defaults(handler=_analytics)
188
-
189
- opencode = subparsers.add_parser(
190
- "opencode-config",
191
- help="Emit an OpenCode-compatible MaramaRoute provider config.",
192
- )
193
- opencode.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
194
- opencode.add_argument("--base-url", default="http://127.0.0.1:8787/v1")
195
- opencode.set_defaults(handler=_opencode_config)
196
-
197
- ui = subparsers.add_parser(
198
- "ui",
199
- help="Launch the local MaramaRoute browser platform.",
200
- )
201
- ui.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
202
- ui.add_argument("--host", type=str, default="127.0.0.1")
203
- ui.add_argument("--port", type=int, default=8787)
204
- ui.add_argument("--open", action=argparse.BooleanOptionalAction, default=False)
205
- ui.add_argument("--smoke", action=argparse.BooleanOptionalAction, default=False)
206
- ui.set_defaults(handler=_ui)
207
-
208
- serve = subparsers.add_parser(
209
- "serve",
210
- help="Run the local OpenAI-compatible MaramaRoute gateway and browser console.",
211
- )
212
- serve.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
213
- serve.add_argument("--config", type=Path, default=None, help="Gateway backend config JSON.")
214
- serve.add_argument("--host", type=str, default="127.0.0.1")
215
- serve.add_argument("--port", type=int, default=8787)
216
- serve.add_argument("--open", action=argparse.BooleanOptionalAction, default=False)
217
- serve.add_argument("--smoke", action=argparse.BooleanOptionalAction, default=False)
218
- serve.set_defaults(handler=_serve)
219
- return parser
220
-
221
-
222
- def main(argv: Sequence[str] | None = None) -> int:
223
- parser = build_parser()
224
- args = parser.parse_args(argv)
225
- handler = getattr(args, "handler", None)
226
- if handler is None:
227
- parser.print_help()
228
- return 0
229
- return int(handler(args))
230
-
231
-
232
- if __name__ == "__main__":
233
- raise SystemExit(main())
 
1
+ from __future__ import annotations
2
+
3
+ import argparse
4
+ import json
5
+ from collections.abc import Sequence
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ from .gateway import build_models_response, route_chat_payload
10
+ from .platform import (
11
+ build_opencode_provider_config,
12
+ build_registry_analytics,
13
+ catalog_models,
14
+ compare_models,
15
+ route_scenario_matrix,
16
+ )
17
+ from .registry import RoutingRequest, load_model_registry
18
+ from .router import SovereignModelRouter
19
+
20
+
21
+ def _load_json_mapping(path: Path) -> dict[str, Any]:
22
+ payload = json.loads(path.read_text(encoding="utf-8-sig"))
23
+ if not isinstance(payload, dict):
24
+ raise ValueError(f"Expected mapping in {path}")
25
+ return payload
26
+
27
+
28
+ def _route(args: argparse.Namespace) -> int:
29
+ models = load_model_registry(args.registry)
30
+ payload = _load_json_mapping(args.request)
31
+ decision = SovereignModelRouter(models).route(RoutingRequest.from_payload(payload))
32
+ print(json.dumps(decision.to_dict(), indent=2, sort_keys=True))
33
+ return 0 if decision.selected_model is not None else 2
34
+
35
+
36
+ def _models(args: argparse.Namespace) -> int:
37
+ models = load_model_registry(args.registry)
38
+ print(json.dumps(build_models_response(models), indent=2, sort_keys=True))
39
+ return 0
40
+
41
+
42
+ def _chat_dry_run(args: argparse.Namespace) -> int:
43
+ models = load_model_registry(args.registry)
44
+ payload = _load_json_mapping(args.request)
45
+ result = route_chat_payload(payload, models)
46
+ print(json.dumps(result, indent=2, sort_keys=True))
47
+ selected = result["route_decision"]["selected_model"]
48
+ return 0 if selected is not None else 2
49
+
50
+
51
+ def _catalog(args: argparse.Namespace) -> int:
52
+ models = load_model_registry(args.registry)
53
+ result = catalog_models(
54
+ models,
55
+ {
56
+ "search": args.search,
57
+ "task_type": args.task,
58
+ "runtime": args.runtime,
59
+ "modality": args.modality,
60
+ "jurisdiction": args.jurisdiction,
61
+ "min_context_tokens": args.min_context_tokens,
62
+ "requires_json": args.requires_json,
63
+ "requires_tools": args.requires_tools,
64
+ "requires_local": args.requires_local,
65
+ "limit": args.limit,
66
+ },
67
+ )
68
+ print(json.dumps(result, indent=2, sort_keys=True))
69
+ return 0
70
+
71
+
72
+ def _compare(args: argparse.Namespace) -> int:
73
+ models = load_model_registry(args.registry)
74
+ model_ids = [item.strip() for value in args.model for item in value.split(",") if item.strip()]
75
+ request = _load_json_mapping(args.request) if args.request else None
76
+ result = compare_models(models, model_ids, request)
77
+ print(json.dumps(result, indent=2, sort_keys=True))
78
+ return 0 if result["ok"] else 2
79
+
80
+
81
+ def _matrix(args: argparse.Namespace) -> int:
82
+ models = load_model_registry(args.registry)
83
+ result = route_scenario_matrix(models)
84
+ print(json.dumps(result, indent=2, sort_keys=True))
85
+ return 0 if result["ok"] or args.allow_blocked_exit_zero else 2
86
+
87
+
88
+ def _analytics(args: argparse.Namespace) -> int:
89
+ print(json.dumps(build_registry_analytics(load_model_registry(args.registry)), indent=2, sort_keys=True))
90
+ return 0
91
+
92
+
93
+ def _opencode_config(args: argparse.Namespace) -> int:
94
+ models = load_model_registry(args.registry)
95
+ result = build_opencode_provider_config(models, base_url=args.base_url)
96
+ print(json.dumps(result, indent=2, sort_keys=True))
97
+ return 0
98
+
99
+
100
+ def _ui(args: argparse.Namespace) -> int:
101
+ from .ui import run_ui
102
+
103
+ return run_ui(
104
+ registry_path=args.registry,
105
+ host=args.host,
106
+ port=args.port,
107
+ open_browser=args.open,
108
+ smoke=args.smoke,
109
+ )
110
+
111
+
112
+ def _serve(args: argparse.Namespace) -> int:
113
+ from .server import serve_gateway
114
+
115
+ return serve_gateway(
116
+ registry_path=args.registry,
117
+ config_path=args.config,
118
+ host=args.host,
119
+ port=args.port,
120
+ open_browser=args.open,
121
+ smoke=args.smoke,
122
+ )
123
+
124
+
125
+ def build_parser() -> argparse.ArgumentParser:
126
+ parser = argparse.ArgumentParser(
127
+ prog="lumynax-marama-route",
128
+ description="Route requests across LumynaX sovereign model releases.",
129
+ )
130
+ subparsers = parser.add_subparsers(dest="command")
131
+ route = subparsers.add_parser("route", help="Select a LumynaX model for a request.")
132
+ route.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
133
+ route.add_argument("--request", type=Path, required=True, help="Routing request JSON.")
134
+ route.set_defaults(handler=_route)
135
+
136
+ models = subparsers.add_parser(
137
+ "models",
138
+ help="Emit an OpenAI-compatible /v1/models response.",
139
+ )
140
+ models.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
141
+ models.set_defaults(handler=_models)
142
+
143
+ chat = subparsers.add_parser(
144
+ "chat-dry-run",
145
+ help="Route an OpenAI-compatible chat request without invoking a backend.",
146
+ )
147
+ chat.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
148
+ chat.add_argument("--request", type=Path, required=True, help="OpenAI chat request JSON.")
149
+ chat.set_defaults(handler=_chat_dry_run)
150
+
151
+ catalog = subparsers.add_parser(
152
+ "catalog",
153
+ help="Search and filter the MaramaRoute model catalog.",
154
+ )
155
+ catalog.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
156
+ catalog.add_argument("--search", default="")
157
+ catalog.add_argument("--task", default="")
158
+ catalog.add_argument("--runtime", default="")
159
+ catalog.add_argument("--modality", default="")
160
+ catalog.add_argument("--jurisdiction", default="NZ")
161
+ catalog.add_argument("--min-context-tokens", type=int, default=0)
162
+ catalog.add_argument("--requires-json", action=argparse.BooleanOptionalAction, default=False)
163
+ catalog.add_argument("--requires-tools", action=argparse.BooleanOptionalAction, default=False)
164
+ catalog.add_argument("--requires-local", action=argparse.BooleanOptionalAction, default=False)
165
+ catalog.add_argument("--limit", type=int, default=25)
166
+ catalog.set_defaults(handler=_catalog)
167
+
168
+ compare = subparsers.add_parser(
169
+ "compare",
170
+ help="Compare routed fit for selected model ids.",
171
+ )
172
+ compare.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
173
+ compare.add_argument("--model", action="append", required=True, help="Model id, repeatable or comma-separated.")
174
+ compare.add_argument("--request", type=Path, default=None, help="Optional routing request JSON.")
175
+ compare.set_defaults(handler=_compare)
176
+
177
+ matrix = subparsers.add_parser(
178
+ "matrix",
179
+ help="Run the built-in sovereign routing scenario matrix.",
180
+ )
181
+ matrix.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
182
+ matrix.add_argument("--allow-blocked-exit-zero", action=argparse.BooleanOptionalAction, default=False)
183
+ matrix.set_defaults(handler=_matrix)
184
+
185
+ analytics = subparsers.add_parser("analytics", help="Summarise registry coverage.")
186
+ analytics.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
187
+ analytics.set_defaults(handler=_analytics)
188
+
189
+ opencode = subparsers.add_parser(
190
+ "opencode-config",
191
+ help="Emit an OpenCode-compatible MaramaRoute provider config.",
192
+ )
193
+ opencode.add_argument("--registry", type=Path, required=True, help="MaramaRoute model registry JSON.")
194
+ opencode.add_argument("--base-url", default="http://127.0.0.1:8787/v1")
195
+ opencode.set_defaults(handler=_opencode_config)
196
+
197
+ ui = subparsers.add_parser(
198
+ "ui",
199
+ help="Launch the local MaramaRoute browser platform.",
200
+ )
201
+ ui.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
202
+ ui.add_argument("--host", type=str, default="127.0.0.1")
203
+ ui.add_argument("--port", type=int, default=8787)
204
+ ui.add_argument("--open", action=argparse.BooleanOptionalAction, default=False)
205
+ ui.add_argument("--smoke", action=argparse.BooleanOptionalAction, default=False)
206
+ ui.set_defaults(handler=_ui)
207
+
208
+ serve = subparsers.add_parser(
209
+ "serve",
210
+ help="Run the local OpenAI-compatible MaramaRoute gateway and browser console.",
211
+ )
212
+ serve.add_argument("--registry", type=Path, default=None, help="MaramaRoute model registry JSON.")
213
+ serve.add_argument("--config", type=Path, default=None, help="Gateway backend config JSON.")
214
+ serve.add_argument("--host", type=str, default="127.0.0.1")
215
+ serve.add_argument("--port", type=int, default=8787)
216
+ serve.add_argument("--open", action=argparse.BooleanOptionalAction, default=False)
217
+ serve.add_argument("--smoke", action=argparse.BooleanOptionalAction, default=False)
218
+ serve.set_defaults(handler=_serve)
219
+ return parser
220
+
221
+
222
+ def main(argv: Sequence[str] | None = None) -> int:
223
+ parser = build_parser()
224
+ args = parser.parse_args(argv)
225
+ handler = getattr(args, "handler", None)
226
+ if handler is None:
227
+ parser.print_help()
228
+ return 0
229
+ return int(handler(args))
230
+
231
+
232
+ if __name__ == "__main__":
233
+ raise SystemExit(main())
marama_route/configs/gateway.local.json CHANGED
@@ -1,13 +1,13 @@
1
- {
2
- "mode": "route_only",
3
- "prompt_retention": "not_stored_by_default",
4
- "default_timeout_seconds": 120,
5
- "backends": {
6
- "example-local-openai-compatible": {
7
- "type": "openai_compatible",
8
- "base_url": "http://127.0.0.1:8000/v1",
9
- "api_key_env": "",
10
- "model": "local-model-id"
11
- }
12
- }
13
- }
 
1
+ {
2
+ "mode": "route_only",
3
+ "prompt_retention": "not_stored_by_default",
4
+ "default_timeout_seconds": 120,
5
+ "backends": {
6
+ "example-local-openai-compatible": {
7
+ "type": "openai_compatible",
8
+ "base_url": "http://127.0.0.1:8000/v1",
9
+ "api_key_env": "",
10
+ "model": "local-model-id"
11
+ }
12
+ }
13
+ }
marama_route/configs/service.local.json CHANGED
@@ -1,14 +1,14 @@
1
- {
2
- "ledger_path": ".sovereigncode/audit.jsonl",
3
- "default_region": "NZ",
4
- "fail_closed": true,
5
- "require_human_review_for": [
6
- "write_files",
7
- "execute_shell",
8
- "network_export",
9
- "commit",
10
- "publish",
11
- "train_model"
12
- ],
13
- "marama_route_base_url": "http://127.0.0.1:8787/v1"
14
- }
 
1
+ {
2
+ "ledger_path": ".sovereigncode/audit.jsonl",
3
+ "default_region": "NZ",
4
+ "fail_closed": true,
5
+ "require_human_review_for": [
6
+ "write_files",
7
+ "execute_shell",
8
+ "network_export",
9
+ "commit",
10
+ "publish",
11
+ "train_model"
12
+ ],
13
+ "marama_route_base_url": "http://127.0.0.1:8787/v1"
14
+ }
marama_route/py.typed ADDED
File without changes
marama_route/server.py CHANGED
@@ -1,312 +1,312 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import os
5
- import tempfile
6
- import urllib.error
7
- import urllib.request
8
- from pathlib import Path
9
- from typing import Any
10
-
11
- try: # repo package
12
- from tinyluminax.products._ui_server import serve_dashboard
13
- except ModuleNotFoundError: # standalone HF package
14
- from ._ui_server import serve_dashboard
15
-
16
- from .gateway import route_chat_payload
17
- from .platform import build_models_api, route_or_chat_payload, route_receipt
18
- from .registry import load_model_registry
19
- from .ui import (
20
- PRODUCT_NAME,
21
- build_dashboard_state,
22
- build_expanded_dashboard_html,
23
- default_openai_chat_request_path,
24
- default_registry_path,
25
- handle_api_request,
26
- load_json_mapping,
27
- )
28
-
29
- PACKAGE_ROOT = Path(__file__).resolve().parent
30
- PACKAGE_PARENT = PACKAGE_ROOT.parent
31
-
32
- DEFAULT_GATEWAY_CONFIG: dict[str, Any] = {
33
- "mode": "route_only",
34
- "prompt_retention": "not_stored_by_default",
35
- "default_timeout_seconds": 120,
36
- "backends": {},
37
- }
38
-
39
-
40
- def default_gateway_config_path() -> Path:
41
- candidates = [
42
- Path.cwd() / "products" / "lumynax-marama-route" / "configs" / "gateway.local.json",
43
- Path.cwd() / "configs" / "gateway.local.json",
44
- PACKAGE_ROOT / "configs" / "gateway.local.json",
45
- PACKAGE_PARENT / "configs" / "gateway.local.json",
46
- ]
47
- for path in candidates:
48
- if path.exists():
49
- return path
50
- return candidates[0]
51
-
52
-
53
- def default_route_request_path() -> Path:
54
- candidates = [
55
- Path.cwd() / "products" / "lumynax-marama-route" / "examples" / "request.code-restricted.json",
56
- Path.cwd() / "examples" / "request.code-restricted.json",
57
- PACKAGE_ROOT / "examples" / "request.code-restricted.json",
58
- PACKAGE_PARENT / "examples" / "request.code-restricted.json",
59
- ]
60
- for path in candidates:
61
- if path.exists():
62
- return path
63
- return candidates[0]
64
-
65
-
66
- def load_gateway_config(path: Path | None = None) -> dict[str, Any]:
67
- config = dict(DEFAULT_GATEWAY_CONFIG)
68
- config["backends"] = dict(DEFAULT_GATEWAY_CONFIG["backends"])
69
- resolved = path or default_gateway_config_path()
70
- if resolved.exists():
71
- payload = json.loads(resolved.read_text(encoding="utf-8-sig"))
72
- if not isinstance(payload, dict):
73
- raise ValueError(f"Expected gateway config object in {resolved}")
74
- config.update(payload)
75
- config["backends"] = dict(payload.get("backends") or {})
76
- config["config_path"] = str(resolved)
77
- return config
78
-
79
-
80
- def handle_gateway_request(
81
- method: str,
82
- path: str,
83
- payload: dict[str, Any] | None,
84
- registry_path: Path,
85
- config_path: Path | None = None,
86
- ) -> tuple[int, dict[str, Any]]:
87
- models = load_model_registry(registry_path)
88
- config = load_gateway_config(config_path)
89
-
90
- if path.startswith("/api/"):
91
- return handle_api_request(method, path, payload, registry_path)
92
- if method == "GET" and path in {"/health", "/v1/health"}:
93
- return 200, {
94
- "ok": True,
95
- "product": PRODUCT_NAME,
96
- "mode": config["mode"],
97
- "model_count": len(models),
98
- "configured_backends": len(config.get("backends") or {}),
99
- "prompt_retention": config.get("prompt_retention", "not_stored_by_default"),
100
- }
101
- if method == "GET" and path == "/v1/models":
102
- return 200, build_models_api(models)
103
- if method == "POST" and path == "/v1/route" and payload is not None:
104
- result = route_or_chat_payload(payload, models)
105
- return (200 if result["ok"] else 422), result
106
- if method == "POST" and path == "/v1/chat/completions" and payload is not None:
107
- return chat_completion_gateway(payload, models, config)
108
- return 404, {"ok": False, "error": "not_found"}
109
-
110
-
111
- def chat_completion_gateway(
112
- payload: dict[str, Any],
113
- models: tuple[Any, ...],
114
- config: dict[str, Any],
115
- ) -> tuple[int, dict[str, Any]]:
116
- route_result = route_chat_payload(payload, models)
117
- decision = route_result["route_decision"]
118
- selected = decision.get("selected_model")
119
- if not isinstance(selected, dict):
120
- return 422, {"ok": False, "error": "no_eligible_model", **route_result}
121
-
122
- receipt = route_receipt(payload, route_result)
123
- dry_run = bool(
124
- payload.get("dry_run")
125
- or payload.get("marama_route_dry_run")
126
- or config.get("mode", "route_only") == "route_only"
127
- )
128
- if dry_run:
129
- response = dict(route_result["chat_completion_response"])
130
- response["marama_route"] = dict(response["marama_route"])
131
- response["marama_route"].update(
132
- {
133
- "backend_mode": "route_only",
134
- "receipt": receipt,
135
- "prompt_retention": config.get("prompt_retention", "not_stored_by_default"),
136
- },
137
- )
138
- return 200, response
139
-
140
- backend = _backend_for_model(selected["model_id"], config)
141
- if backend is None:
142
- return 424, {
143
- "ok": False,
144
- "error": "backend_not_configured",
145
- "message": "Routing succeeded, but no live backend is configured for the selected model.",
146
- "selected_model": selected["model_id"],
147
- "required_config": {
148
- "mode": "live",
149
- "backends": {
150
- selected["model_id"]: {
151
- "type": "openai_compatible",
152
- "base_url": "http://127.0.0.1:8000/v1",
153
- "api_key_env": "OPTIONAL_ENV_NAME",
154
- },
155
- },
156
- },
157
- "receipt": receipt,
158
- **route_result,
159
- }
160
- return _proxy_openai_chat_completion(payload, selected, backend, config, route_result, receipt)
161
-
162
-
163
- def smoke_gateway(
164
- *,
165
- registry_path: Path | None = None,
166
- config_path: Path | None = None,
167
- ) -> dict[str, Any]:
168
- resolved_registry = registry_path or default_registry_path()
169
- resolved_config = config_path or _temporary_route_only_config()
170
- route_payload = load_json_mapping(default_route_request_path())
171
- chat_payload = load_json_mapping(default_openai_chat_request_path())
172
- chat_payload["dry_run"] = True
173
-
174
- health_status, health = handle_gateway_request("GET", "/health", None, resolved_registry, resolved_config)
175
- models_status, models = handle_gateway_request("GET", "/v1/models", None, resolved_registry, resolved_config)
176
- route_status, route = handle_gateway_request("POST", "/v1/route", route_payload, resolved_registry, resolved_config)
177
- chat_status, chat = handle_gateway_request(
178
- "POST",
179
- "/v1/chat/completions",
180
- chat_payload,
181
- resolved_registry,
182
- resolved_config,
183
- )
184
-
185
- if health_status != 200 or models_status != 200 or route_status != 200 or chat_status != 200:
186
- raise RuntimeError("MaramaRoute gateway smoke failed")
187
- if chat.get("object") != "chat.completion" or chat["marama_route"]["selected_model"] is None:
188
- raise RuntimeError("MaramaRoute gateway did not return a routed chat response")
189
- return {
190
- "ok": True,
191
- "product": PRODUCT_NAME,
192
- "mode": health["mode"],
193
- "model_count": health["model_count"],
194
- "route_selected_model": route["route_decision"]["selected_model"]["model_id"],
195
- "chat_selected_model": chat["marama_route"]["selected_model"]["model_id"],
196
- "configured_backends": health["configured_backends"],
197
- }
198
-
199
-
200
- def serve_gateway(
201
- *,
202
- registry_path: Path | None = None,
203
- config_path: Path | None = None,
204
- host: str = "127.0.0.1",
205
- port: int = 8787,
206
- open_browser: bool = False,
207
- smoke: bool = False,
208
- ) -> int:
209
- resolved_registry = registry_path or default_registry_path()
210
- if smoke:
211
- print(json.dumps(smoke_gateway(registry_path=resolved_registry, config_path=config_path), indent=2, sort_keys=True))
212
- return 0
213
-
214
- html = build_expanded_dashboard_html(build_dashboard_state(resolved_registry))
215
- return serve_dashboard(
216
- product_name=f"{PRODUCT_NAME} Gateway",
217
- html=html,
218
- api_handler=lambda method, path, request_payload: handle_gateway_request(
219
- method,
220
- path,
221
- request_payload,
222
- resolved_registry,
223
- config_path,
224
- ),
225
- host=host,
226
- port=port,
227
- open_browser=open_browser,
228
- api_path_prefixes=("/api/", "/v1/"),
229
- api_exact_paths=("/health",),
230
- )
231
-
232
-
233
- def _backend_for_model(model_id: str, config: dict[str, Any]) -> dict[str, Any] | None:
234
- backends = config.get("backends")
235
- if not isinstance(backends, dict):
236
- return None
237
- backend = backends.get(model_id) or backends.get("*")
238
- return dict(backend) if isinstance(backend, dict) else None
239
-
240
-
241
- def _proxy_openai_chat_completion(
242
- payload: dict[str, Any],
243
- selected: dict[str, Any],
244
- backend: dict[str, Any],
245
- config: dict[str, Any],
246
- route_result: dict[str, Any],
247
- receipt: dict[str, Any],
248
- ) -> tuple[int, dict[str, Any]]:
249
- if str(backend.get("type") or "openai_compatible") != "openai_compatible":
250
- return 424, {"ok": False, "error": "unsupported_backend_type", "backend": backend}
251
-
252
- base_url = str(backend.get("base_url") or "").rstrip("/")
253
- if not base_url:
254
- return 424, {"ok": False, "error": "backend_base_url_missing", "selected_model": selected["model_id"]}
255
- endpoint = f"{base_url}/chat/completions"
256
- upstream_payload = dict(payload)
257
- upstream_payload["model"] = str(backend.get("model") or selected["model_id"])
258
- for key in ("route", "routing", "dry_run", "marama_route_dry_run"):
259
- upstream_payload.pop(key, None)
260
-
261
- headers = {"Content-Type": "application/json"}
262
- api_key_env = str(backend.get("api_key_env") or "")
263
- if api_key_env and os.getenv(api_key_env):
264
- headers["Authorization"] = f"Bearer {os.environ[api_key_env]}"
265
- headers.update({str(key): str(value) for key, value in dict(backend.get("headers") or {}).items()})
266
-
267
- timeout = float(backend.get("timeout_seconds") or config.get("default_timeout_seconds") or 120)
268
- request = urllib.request.Request(
269
- endpoint,
270
- data=json.dumps(upstream_payload).encode("utf-8"),
271
- headers=headers,
272
- method="POST",
273
- )
274
- try:
275
- with urllib.request.urlopen(request, timeout=timeout) as response: # noqa: S310 - operator-configured local/remote backend
276
- body = response.read().decode("utf-8")
277
- payload_out = json.loads(body)
278
- if not isinstance(payload_out, dict):
279
- raise ValueError("upstream response was not a JSON object")
280
- payload_out["marama_route"] = {
281
- "dry_run": False,
282
- "selected_model": selected,
283
- "fallback_models": route_result["route_decision"]["fallback_models"],
284
- "rejected_count": len(route_result["route_decision"]["rejected"]),
285
- "receipt": receipt,
286
- "backend_base_url": base_url,
287
- "prompt_retention": config.get("prompt_retention", "not_stored_by_default"),
288
- }
289
- return int(response.status), payload_out
290
- except urllib.error.HTTPError as exc:
291
- return exc.code, {
292
- "ok": False,
293
- "error": "backend_http_error",
294
- "status": exc.code,
295
- "body": exc.read().decode("utf-8", errors="replace"),
296
- "receipt": receipt,
297
- **route_result,
298
- }
299
- except Exception as exc:
300
- return 502, {
301
- "ok": False,
302
- "error": "backend_unavailable",
303
- "message": str(exc),
304
- "receipt": receipt,
305
- **route_result,
306
- }
307
-
308
-
309
- def _temporary_route_only_config() -> Path:
310
- path = Path(tempfile.gettempdir()) / "marama-route-smoke.gateway.json"
311
- path.write_text(json.dumps(DEFAULT_GATEWAY_CONFIG, indent=2, sort_keys=True), encoding="utf-8")
312
- return path
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import tempfile
6
+ import urllib.error
7
+ import urllib.request
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ try: # repo package
12
+ from tinyluminax.products._ui_server import serve_dashboard
13
+ except ModuleNotFoundError: # standalone HF package
14
+ from ._ui_server import serve_dashboard
15
+
16
+ from .gateway import route_chat_payload
17
+ from .platform import build_models_api, route_or_chat_payload, route_receipt
18
+ from .registry import load_model_registry
19
+ from .ui import (
20
+ PRODUCT_NAME,
21
+ build_dashboard_state,
22
+ build_expanded_dashboard_html,
23
+ default_openai_chat_request_path,
24
+ default_registry_path,
25
+ handle_api_request,
26
+ load_json_mapping,
27
+ )
28
+
29
+ PACKAGE_ROOT = Path(__file__).resolve().parent
30
+ PACKAGE_PARENT = PACKAGE_ROOT.parent
31
+
32
+ DEFAULT_GATEWAY_CONFIG: dict[str, Any] = {
33
+ "mode": "route_only",
34
+ "prompt_retention": "not_stored_by_default",
35
+ "default_timeout_seconds": 120,
36
+ "backends": {},
37
+ }
38
+
39
+
40
+ def default_gateway_config_path() -> Path:
41
+ candidates = [
42
+ Path.cwd() / "products" / "lumynax-marama-route" / "configs" / "gateway.local.json",
43
+ Path.cwd() / "configs" / "gateway.local.json",
44
+ PACKAGE_ROOT / "configs" / "gateway.local.json",
45
+ PACKAGE_PARENT / "configs" / "gateway.local.json",
46
+ ]
47
+ for path in candidates:
48
+ if path.exists():
49
+ return path
50
+ return candidates[0]
51
+
52
+
53
+ def default_route_request_path() -> Path:
54
+ candidates = [
55
+ Path.cwd() / "products" / "lumynax-marama-route" / "examples" / "request.code-restricted.json",
56
+ Path.cwd() / "examples" / "request.code-restricted.json",
57
+ PACKAGE_ROOT / "examples" / "request.code-restricted.json",
58
+ PACKAGE_PARENT / "examples" / "request.code-restricted.json",
59
+ ]
60
+ for path in candidates:
61
+ if path.exists():
62
+ return path
63
+ return candidates[0]
64
+
65
+
66
+ def load_gateway_config(path: Path | None = None) -> dict[str, Any]:
67
+ config = dict(DEFAULT_GATEWAY_CONFIG)
68
+ config["backends"] = dict(DEFAULT_GATEWAY_CONFIG["backends"])
69
+ resolved = path or default_gateway_config_path()
70
+ if resolved.exists():
71
+ payload = json.loads(resolved.read_text(encoding="utf-8-sig"))
72
+ if not isinstance(payload, dict):
73
+ raise ValueError(f"Expected gateway config object in {resolved}")
74
+ config.update(payload)
75
+ config["backends"] = dict(payload.get("backends") or {})
76
+ config["config_path"] = str(resolved)
77
+ return config
78
+
79
+
80
+ def handle_gateway_request(
81
+ method: str,
82
+ path: str,
83
+ payload: dict[str, Any] | None,
84
+ registry_path: Path,
85
+ config_path: Path | None = None,
86
+ ) -> tuple[int, dict[str, Any]]:
87
+ models = load_model_registry(registry_path)
88
+ config = load_gateway_config(config_path)
89
+
90
+ if path.startswith("/api/"):
91
+ return handle_api_request(method, path, payload, registry_path)
92
+ if method == "GET" and path in {"/health", "/v1/health"}:
93
+ return 200, {
94
+ "ok": True,
95
+ "product": PRODUCT_NAME,
96
+ "mode": config["mode"],
97
+ "model_count": len(models),
98
+ "configured_backends": len(config.get("backends") or {}),
99
+ "prompt_retention": config.get("prompt_retention", "not_stored_by_default"),
100
+ }
101
+ if method == "GET" and path == "/v1/models":
102
+ return 200, build_models_api(models)
103
+ if method == "POST" and path == "/v1/route" and payload is not None:
104
+ result = route_or_chat_payload(payload, models)
105
+ return (200 if result["ok"] else 422), result
106
+ if method == "POST" and path == "/v1/chat/completions" and payload is not None:
107
+ return chat_completion_gateway(payload, models, config)
108
+ return 404, {"ok": False, "error": "not_found"}
109
+
110
+
111
+ def chat_completion_gateway(
112
+ payload: dict[str, Any],
113
+ models: tuple[Any, ...],
114
+ config: dict[str, Any],
115
+ ) -> tuple[int, dict[str, Any]]:
116
+ route_result = route_chat_payload(payload, models)
117
+ decision = route_result["route_decision"]
118
+ selected = decision.get("selected_model")
119
+ if not isinstance(selected, dict):
120
+ return 422, {"ok": False, "error": "no_eligible_model", **route_result}
121
+
122
+ receipt = route_receipt(payload, route_result)
123
+ dry_run = bool(
124
+ payload.get("dry_run")
125
+ or payload.get("marama_route_dry_run")
126
+ or config.get("mode", "route_only") == "route_only"
127
+ )
128
+ if dry_run:
129
+ response = dict(route_result["chat_completion_response"])
130
+ response["marama_route"] = dict(response["marama_route"])
131
+ response["marama_route"].update(
132
+ {
133
+ "backend_mode": "route_only",
134
+ "receipt": receipt,
135
+ "prompt_retention": config.get("prompt_retention", "not_stored_by_default"),
136
+ },
137
+ )
138
+ return 200, response
139
+
140
+ backend = _backend_for_model(selected["model_id"], config)
141
+ if backend is None:
142
+ return 424, {
143
+ "ok": False,
144
+ "error": "backend_not_configured",
145
+ "message": "Routing succeeded, but no live backend is configured for the selected model.",
146
+ "selected_model": selected["model_id"],
147
+ "required_config": {
148
+ "mode": "live",
149
+ "backends": {
150
+ selected["model_id"]: {
151
+ "type": "openai_compatible",
152
+ "base_url": "http://127.0.0.1:8000/v1",
153
+ "api_key_env": "OPTIONAL_ENV_NAME",
154
+ },
155
+ },
156
+ },
157
+ "receipt": receipt,
158
+ **route_result,
159
+ }
160
+ return _proxy_openai_chat_completion(payload, selected, backend, config, route_result, receipt)
161
+
162
+
163
+ def smoke_gateway(
164
+ *,
165
+ registry_path: Path | None = None,
166
+ config_path: Path | None = None,
167
+ ) -> dict[str, Any]:
168
+ resolved_registry = registry_path or default_registry_path()
169
+ resolved_config = config_path or _temporary_route_only_config()
170
+ route_payload = load_json_mapping(default_route_request_path())
171
+ chat_payload = load_json_mapping(default_openai_chat_request_path())
172
+ chat_payload["dry_run"] = True
173
+
174
+ health_status, health = handle_gateway_request("GET", "/health", None, resolved_registry, resolved_config)
175
+ models_status, models = handle_gateway_request("GET", "/v1/models", None, resolved_registry, resolved_config)
176
+ route_status, route = handle_gateway_request("POST", "/v1/route", route_payload, resolved_registry, resolved_config)
177
+ chat_status, chat = handle_gateway_request(
178
+ "POST",
179
+ "/v1/chat/completions",
180
+ chat_payload,
181
+ resolved_registry,
182
+ resolved_config,
183
+ )
184
+
185
+ if health_status != 200 or models_status != 200 or route_status != 200 or chat_status != 200:
186
+ raise RuntimeError("MaramaRoute gateway smoke failed")
187
+ if chat.get("object") != "chat.completion" or chat["marama_route"]["selected_model"] is None:
188
+ raise RuntimeError("MaramaRoute gateway did not return a routed chat response")
189
+ return {
190
+ "ok": True,
191
+ "product": PRODUCT_NAME,
192
+ "mode": health["mode"],
193
+ "model_count": health["model_count"],
194
+ "route_selected_model": route["route_decision"]["selected_model"]["model_id"],
195
+ "chat_selected_model": chat["marama_route"]["selected_model"]["model_id"],
196
+ "configured_backends": health["configured_backends"],
197
+ }
198
+
199
+
200
+ def serve_gateway(
201
+ *,
202
+ registry_path: Path | None = None,
203
+ config_path: Path | None = None,
204
+ host: str = "127.0.0.1",
205
+ port: int = 8787,
206
+ open_browser: bool = False,
207
+ smoke: bool = False,
208
+ ) -> int:
209
+ resolved_registry = registry_path or default_registry_path()
210
+ if smoke:
211
+ print(json.dumps(smoke_gateway(registry_path=resolved_registry, config_path=config_path), indent=2, sort_keys=True))
212
+ return 0
213
+
214
+ html = build_expanded_dashboard_html(build_dashboard_state(resolved_registry))
215
+ return serve_dashboard(
216
+ product_name=f"{PRODUCT_NAME} Gateway",
217
+ html=html,
218
+ api_handler=lambda method, path, request_payload: handle_gateway_request(
219
+ method,
220
+ path,
221
+ request_payload,
222
+ resolved_registry,
223
+ config_path,
224
+ ),
225
+ host=host,
226
+ port=port,
227
+ open_browser=open_browser,
228
+ api_path_prefixes=("/api/", "/v1/"),
229
+ api_exact_paths=("/health",),
230
+ )
231
+
232
+
233
+ def _backend_for_model(model_id: str, config: dict[str, Any]) -> dict[str, Any] | None:
234
+ backends = config.get("backends")
235
+ if not isinstance(backends, dict):
236
+ return None
237
+ backend = backends.get(model_id) or backends.get("*")
238
+ return dict(backend) if isinstance(backend, dict) else None
239
+
240
+
241
+ def _proxy_openai_chat_completion(
242
+ payload: dict[str, Any],
243
+ selected: dict[str, Any],
244
+ backend: dict[str, Any],
245
+ config: dict[str, Any],
246
+ route_result: dict[str, Any],
247
+ receipt: dict[str, Any],
248
+ ) -> tuple[int, dict[str, Any]]:
249
+ if str(backend.get("type") or "openai_compatible") != "openai_compatible":
250
+ return 424, {"ok": False, "error": "unsupported_backend_type", "backend": backend}
251
+
252
+ base_url = str(backend.get("base_url") or "").rstrip("/")
253
+ if not base_url:
254
+ return 424, {"ok": False, "error": "backend_base_url_missing", "selected_model": selected["model_id"]}
255
+ endpoint = f"{base_url}/chat/completions"
256
+ upstream_payload = dict(payload)
257
+ upstream_payload["model"] = str(backend.get("model") or selected["model_id"])
258
+ for key in ("route", "routing", "dry_run", "marama_route_dry_run"):
259
+ upstream_payload.pop(key, None)
260
+
261
+ headers = {"Content-Type": "application/json"}
262
+ api_key_env = str(backend.get("api_key_env") or "")
263
+ if api_key_env and os.getenv(api_key_env):
264
+ headers["Authorization"] = f"Bearer {os.environ[api_key_env]}"
265
+ headers.update({str(key): str(value) for key, value in dict(backend.get("headers") or {}).items()})
266
+
267
+ timeout = float(backend.get("timeout_seconds") or config.get("default_timeout_seconds") or 120)
268
+ request = urllib.request.Request(
269
+ endpoint,
270
+ data=json.dumps(upstream_payload).encode("utf-8"),
271
+ headers=headers,
272
+ method="POST",
273
+ )
274
+ try:
275
+ with urllib.request.urlopen(request, timeout=timeout) as response: # noqa: S310 - operator-configured local/remote backend
276
+ body = response.read().decode("utf-8")
277
+ payload_out = json.loads(body)
278
+ if not isinstance(payload_out, dict):
279
+ raise ValueError("upstream response was not a JSON object")
280
+ payload_out["marama_route"] = {
281
+ "dry_run": False,
282
+ "selected_model": selected,
283
+ "fallback_models": route_result["route_decision"]["fallback_models"],
284
+ "rejected_count": len(route_result["route_decision"]["rejected"]),
285
+ "receipt": receipt,
286
+ "backend_base_url": base_url,
287
+ "prompt_retention": config.get("prompt_retention", "not_stored_by_default"),
288
+ }
289
+ return int(response.status), payload_out
290
+ except urllib.error.HTTPError as exc:
291
+ return exc.code, {
292
+ "ok": False,
293
+ "error": "backend_http_error",
294
+ "status": exc.code,
295
+ "body": exc.read().decode("utf-8", errors="replace"),
296
+ "receipt": receipt,
297
+ **route_result,
298
+ }
299
+ except Exception as exc:
300
+ return 502, {
301
+ "ok": False,
302
+ "error": "backend_unavailable",
303
+ "message": str(exc),
304
+ "receipt": receipt,
305
+ **route_result,
306
+ }
307
+
308
+
309
+ def _temporary_route_only_config() -> Path:
310
+ path = Path(tempfile.gettempdir()) / "marama-route-smoke.gateway.json"
311
+ path.write_text(json.dumps(DEFAULT_GATEWAY_CONFIG, indent=2, sort_keys=True), encoding="utf-8")
312
+ return path
product_manifest.json CHANGED
@@ -1,62 +1,77 @@
1
- {
2
- "product_name": "AbteeX SovereignCode",
3
- "slug": "abx-sovereigncode",
4
  "publisher": "AbteeX AI Labs",
5
  "family": "LumynaX sovereign products",
6
  "stage": "local_runtime",
7
- "positioning": "OpenCode-style local coding agent with Data Capsule sovereignty controls",
8
- "target_region": "NZ",
9
- "target_users": [
10
- "New Zealand developers",
11
- "regulated SMEs",
12
- "local government teams",
13
- "health-adjacent operators",
14
- "Iwi and community data stewards",
15
- "privacy-conscious individual developers"
16
- ],
17
- "primary_modules": [
18
- "data_capsule_policy",
19
- "personal_detail_consent",
20
- "tool_broker",
21
- "lumynax_runtime_adapter",
22
- "audit_ledger",
23
- "human_review_gate",
24
- "policy_matrix",
25
- "tool_gate_check",
26
- "capsule_summary",
27
- "opencode_workspace_export",
28
- "opencode_compatible_provider",
29
- "policy_api_service",
30
- "persistent_audit_ledger"
31
- ],
32
- "runtime_entrypoints": [
33
- "python -m tinyluminax.products.sovereigncode.cli evaluate",
34
- "python -m tinyluminax.products.sovereigncode.cli plan-turn",
35
- "python -m tinyluminax.products.sovereigncode.cli policy-matrix",
36
- "python -m tinyluminax.products.sovereigncode.cli tool-check",
37
- "python -m tinyluminax.products.sovereigncode.cli opencode-config",
 
 
 
 
 
 
 
 
 
 
 
 
38
  "python -m tinyluminax.products.sovereigncode.cli ui",
39
  "python -m tinyluminax.products.sovereigncode.cli serve",
40
- "python -m tinyluminax.products.sovereigncode.cli audit"
41
- ],
42
- "integration_surfaces": [
43
- "OpenAI-compatible /v1/chat/completions via MaramaRoute",
44
- "OpenAI-compatible /v1/models via MaramaRoute",
45
- "SovereignCode GET /health and GET /v1/audit",
46
- "SovereignCode POST /v1/evaluate",
47
- "SovereignCode POST /v1/plan-turn",
48
- "SovereignCode POST /v1/tool-check",
49
- "OpenCode custom provider config",
50
- "local CLI policy evaluator",
51
- "governed coding-turn planner",
52
- "policy matrix and tool gate checker",
53
- "browser operator checklist",
54
- "browser operator console"
55
  ],
56
- "brand_system": {
57
- "paper": "#fffefa",
58
- "ink": "#0a0a0b",
59
- "accent": "#e08a2c",
60
- "muted": "#726b62"
61
- }
62
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "product_name": "AbteeX SovereignCode",
3
+ "slug": "abx-sovereigncode",
4
  "publisher": "AbteeX AI Labs",
5
  "family": "LumynaX sovereign products",
6
  "stage": "local_runtime",
7
+ "package": {
8
+ "pypi_name": "abteex-sovereigncode",
9
+ "python_import": "sovereigncode",
10
+ "console_script": "sovereigncode",
11
+ "version": "0.4.0",
12
+ "release_artifacts": [
13
+ "wheel",
14
+ "sdist",
15
+ "huggingface_model_repo",
16
+ "github_source"
17
+ ]
18
+ },
19
+ "positioning": "OpenCode-style local coding agent with Data Capsule sovereignty controls",
20
+ "target_region": "NZ",
21
+ "target_users": [
22
+ "New Zealand developers",
23
+ "regulated SMEs",
24
+ "local government teams",
25
+ "health-adjacent operators",
26
+ "Iwi and community data stewards",
27
+ "privacy-conscious individual developers"
28
+ ],
29
+ "primary_modules": [
30
+ "data_capsule_policy",
31
+ "personal_detail_consent",
32
+ "tool_broker",
33
+ "lumynax_runtime_adapter",
34
+ "audit_ledger",
35
+ "human_review_gate",
36
+ "policy_matrix",
37
+ "tool_gate_check",
38
+ "capsule_summary",
39
+ "opencode_workspace_export",
40
+ "opencode_compatible_provider",
41
+ "policy_api_service",
42
+ "persistent_audit_ledger"
43
+ ],
44
+ "runtime_entrypoints": [
45
+ "python -m tinyluminax.products.sovereigncode.cli evaluate",
46
+ "python -m tinyluminax.products.sovereigncode.cli plan-turn",
47
+ "python -m tinyluminax.products.sovereigncode.cli policy-matrix",
48
+ "python -m tinyluminax.products.sovereigncode.cli tool-check",
49
+ "python -m tinyluminax.products.sovereigncode.cli opencode-config",
50
  "python -m tinyluminax.products.sovereigncode.cli ui",
51
  "python -m tinyluminax.products.sovereigncode.cli serve",
52
+ "python -m tinyluminax.products.sovereigncode.cli audit",
53
+ "sovereigncode serve",
54
+ "sovereigncode serve --smoke",
55
+ "sovereigncode audit"
 
 
 
 
 
 
 
 
 
 
 
56
  ],
57
+ "integration_surfaces": [
58
+ "OpenAI-compatible /v1/chat/completions via MaramaRoute",
59
+ "OpenAI-compatible /v1/models via MaramaRoute",
60
+ "SovereignCode GET /health and GET /v1/audit",
61
+ "SovereignCode POST /v1/evaluate",
62
+ "SovereignCode POST /v1/plan-turn",
63
+ "SovereignCode POST /v1/tool-check",
64
+ "OpenCode custom provider config",
65
+ "local CLI policy evaluator",
66
+ "governed coding-turn planner",
67
+ "policy matrix and tool gate checker",
68
+ "browser operator checklist",
69
+ "browser operator console"
70
+ ],
71
+ "brand_system": {
72
+ "paper": "#fffefa",
73
+ "ink": "#0a0a0b",
74
+ "accent": "#e08a2c",
75
+ "muted": "#726b62"
76
+ }
77
+ }
pyproject.toml CHANGED
@@ -4,19 +4,41 @@ build-backend = "setuptools.build_meta"
4
 
5
  [project]
6
  name = "abteex-sovereigncode"
7
- version = "0.3.0"
8
- description = "AbteeX SovereignCode: local-first coding agent with Data Capsule sovereignty controls."
9
  readme = "README.md"
10
  requires-python = ">=3.11"
11
  license = "Apache-2.0"
12
  authors = [{ name = "AbteeX AI Labs" }]
13
- keywords = ["lumynax", "sovereignty", "data-capsule", "coding-agent", "opencode", "new-zealand"]
 
14
  dependencies = ["PyYAML>=6.0"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
 
16
  [project.urls]
17
  Homepage = "https://abteex.com"
18
- Repository = "https://huggingface.co/AbteeXAILab/sovereigncode"
 
19
  Lumynax = "https://lumynax.com"
 
20
 
21
  [project.scripts]
22
  sovereigncode = "sovereigncode.cli:main"
@@ -26,6 +48,9 @@ where = ["."]
26
  include = ["sovereigncode*", "marama_route*"]
27
  namespaces = true
28
 
 
 
 
29
  [tool.setuptools.package-data]
30
- sovereigncode = ["configs/*", "examples/*", "integrations/*", "policy-packs/*", "schemas/*"]
31
- marama_route = ["configs/*", "examples/*", "integrations/*", "schemas/*"]
 
4
 
5
  [project]
6
  name = "abteex-sovereigncode"
7
+ version = "0.4.0"
8
+ description = "AbteeX SovereignCode: local-first policy API, audit ledger, and coding-agent sovereignty controls."
9
  readme = "README.md"
10
  requires-python = ">=3.11"
11
  license = "Apache-2.0"
12
  authors = [{ name = "AbteeX AI Labs" }]
13
+ maintainers = [{ name = "AbteeX AI Labs" }]
14
+ keywords = ["lumynax", "sovereignty", "data-capsule", "coding-agent", "opencode", "new-zealand", "policy-api", "audit-ledger"]
15
  dependencies = ["PyYAML>=6.0"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Environment :: Console",
19
+ "Environment :: Web Environment",
20
+ "Intended Audience :: Developers",
21
+ "Intended Audience :: Information Technology",
22
+ "Operating System :: OS Independent",
23
+ "Programming Language :: Python :: 3",
24
+ "Programming Language :: Python :: 3.11",
25
+ "Programming Language :: Python :: 3.12",
26
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
27
+ "Topic :: Software Development :: Libraries :: Python Modules",
28
+ "Topic :: System :: Systems Administration",
29
+ "Typing :: Typed",
30
+ ]
31
+
32
+ [project.optional-dependencies]
33
+ release = ["build>=1.2", "twine>=5.1"]
34
+ dev = ["build>=1.2", "ruff>=0.6", "twine>=5.1"]
35
 
36
  [project.urls]
37
  Homepage = "https://abteex.com"
38
+ Repository = "https://github.com/Aimaghsoodi/TinyLuminaX"
39
+ "Hugging Face" = "https://huggingface.co/AbteeXAILab/sovereigncode"
40
  Lumynax = "https://lumynax.com"
41
+ Issues = "https://github.com/Aimaghsoodi/TinyLuminaX/issues"
42
 
43
  [project.scripts]
44
  sovereigncode = "sovereigncode.cli:main"
 
48
  include = ["sovereigncode*", "marama_route*"]
49
  namespaces = true
50
 
51
+ [tool.setuptools]
52
+ include-package-data = true
53
+
54
  [tool.setuptools.package-data]
55
+ sovereigncode = ["py.typed", "configs/*", "examples/*", "integrations/*", "policy-packs/*", "schemas/*"]
56
+ marama_route = ["py.typed", "configs/*", "examples/*", "integrations/*", "schemas/*"]
sovereigncode/__init__.py CHANGED
@@ -1,41 +1,41 @@
1
- from __future__ import annotations
2
-
3
- from .audit import AuditRecord, build_audit_record
4
- from .ledger import AuditLedger
5
- from .planner import SovereignCodingTurnPlan, ToolGrant, plan_coding_turn
6
- from .platform import (
7
- build_capsule_summary,
8
- build_opencode_workspace_config,
9
- build_policy_matrix,
10
- build_turn_brief,
11
- check_tool_request,
12
- )
13
- from .policy import (
14
- DataCapsule,
15
- PolicyDecision,
16
- SovereignRequest,
17
- SovereigntyPolicyEngine,
18
- )
19
- from .server import handle_service_request, smoke_service
20
- from .ui import smoke_ui as smoke_ui
21
-
22
- __all__ = [
23
- "AuditRecord",
24
- "AuditLedger",
25
- "DataCapsule",
26
- "PolicyDecision",
27
- "SovereignRequest",
28
- "SovereignCodingTurnPlan",
29
- "SovereigntyPolicyEngine",
30
- "ToolGrant",
31
- "build_audit_record",
32
- "build_capsule_summary",
33
- "build_opencode_workspace_config",
34
- "build_policy_matrix",
35
- "build_turn_brief",
36
- "check_tool_request",
37
- "handle_service_request",
38
- "plan_coding_turn",
39
- "smoke_service",
40
- "smoke_ui",
41
- ]
 
1
+ from __future__ import annotations
2
+
3
+ from .audit import AuditRecord, build_audit_record
4
+ from .ledger import AuditLedger
5
+ from .planner import SovereignCodingTurnPlan, ToolGrant, plan_coding_turn
6
+ from .platform import (
7
+ build_capsule_summary,
8
+ build_opencode_workspace_config,
9
+ build_policy_matrix,
10
+ build_turn_brief,
11
+ check_tool_request,
12
+ )
13
+ from .policy import (
14
+ DataCapsule,
15
+ PolicyDecision,
16
+ SovereignRequest,
17
+ SovereigntyPolicyEngine,
18
+ )
19
+ from .server import handle_service_request, smoke_service
20
+ from .ui import smoke_ui as smoke_ui
21
+
22
+ __all__ = [
23
+ "AuditRecord",
24
+ "AuditLedger",
25
+ "DataCapsule",
26
+ "PolicyDecision",
27
+ "SovereignRequest",
28
+ "SovereignCodingTurnPlan",
29
+ "SovereigntyPolicyEngine",
30
+ "ToolGrant",
31
+ "build_audit_record",
32
+ "build_capsule_summary",
33
+ "build_opencode_workspace_config",
34
+ "build_policy_matrix",
35
+ "build_turn_brief",
36
+ "check_tool_request",
37
+ "handle_service_request",
38
+ "plan_coding_turn",
39
+ "smoke_service",
40
+ "smoke_ui",
41
+ ]
sovereigncode/_ui_server.py CHANGED
@@ -1,121 +1,121 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import socket
5
- import webbrowser
6
- from collections.abc import Callable
7
- from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
8
- from typing import Any
9
- from urllib.parse import urlparse
10
-
11
- ApiHandler = Callable[[str, str, dict[str, Any] | None], tuple[int, dict[str, Any]]]
12
-
13
-
14
- def find_available_port(host: str, preferred_port: int, *, attempts: int = 50) -> int:
15
- start = preferred_port if preferred_port > 0 else 0
16
- if start == 0:
17
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
18
- probe.bind((host, 0))
19
- return int(probe.getsockname()[1])
20
-
21
- for port in range(start, start + attempts):
22
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
23
- probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
24
- try:
25
- probe.bind((host, port))
26
- except OSError:
27
- continue
28
- return port
29
- raise OSError(f"No available port found from {preferred_port} to {preferred_port + attempts - 1}")
30
-
31
-
32
- def serve_dashboard(
33
- *,
34
- product_name: str,
35
- html: str,
36
- api_handler: ApiHandler,
37
- host: str,
38
- port: int,
39
- open_browser: bool = False,
40
- api_path_prefixes: tuple[str, ...] = ("/api/",),
41
- api_exact_paths: tuple[str, ...] = (),
42
- ) -> int:
43
- actual_port = find_available_port(host, port)
44
- exact_paths = set(api_exact_paths)
45
-
46
- def is_api_path(path: str) -> bool:
47
- return path in exact_paths or any(path.startswith(prefix) for prefix in api_path_prefixes)
48
-
49
- class Handler(BaseHTTPRequestHandler):
50
- server_version = "AbteeXProductUI/0.1"
51
-
52
- def do_GET(self) -> None: # noqa: N802 - stdlib handler method name
53
- path = urlparse(self.path).path
54
- if path == "/":
55
- self._send_text(200, html, "text/html; charset=utf-8")
56
- return
57
- if is_api_path(path):
58
- self._send_api("GET", path, None)
59
- return
60
- self._send_json(404, {"ok": False, "error": "not_found"})
61
-
62
- def do_POST(self) -> None: # noqa: N802 - stdlib handler method name
63
- path = urlparse(self.path).path
64
- if not is_api_path(path):
65
- self._send_json(404, {"ok": False, "error": "not_found"})
66
- return
67
- try:
68
- length = int(self.headers.get("Content-Length", "0"))
69
- raw = self.rfile.read(length).decode("utf-8") if length else "{}"
70
- payload = json.loads(raw)
71
- if not isinstance(payload, dict):
72
- raise ValueError("JSON body must be an object")
73
- self._send_api("POST", path, payload)
74
- except Exception as exc: # defensive API boundary
75
- self._send_json(400, {"ok": False, "error": str(exc)})
76
-
77
- def log_message(self, format: str, *args: Any) -> None: # noqa: A002
78
- return
79
-
80
- def _send_api(
81
- self,
82
- method: str,
83
- path: str,
84
- payload: dict[str, Any] | None,
85
- ) -> None:
86
- try:
87
- status, response = api_handler(method, path, payload)
88
- except Exception as exc: # defensive API boundary
89
- status, response = 500, {"ok": False, "error": str(exc)}
90
- self._send_json(status, response)
91
-
92
- def _send_json(self, status: int, payload: dict[str, Any]) -> None:
93
- body = json.dumps(payload, indent=2, sort_keys=True).encode("utf-8")
94
- self.send_response(status)
95
- self.send_header("Content-Type", "application/json; charset=utf-8")
96
- self.send_header("Content-Length", str(len(body)))
97
- self.send_header("Cache-Control", "no-store")
98
- self.end_headers()
99
- self.wfile.write(body)
100
-
101
- def _send_text(self, status: int, body: str, content_type: str) -> None:
102
- encoded = body.encode("utf-8")
103
- self.send_response(status)
104
- self.send_header("Content-Type", content_type)
105
- self.send_header("Content-Length", str(len(encoded)))
106
- self.send_header("Cache-Control", "no-store")
107
- self.end_headers()
108
- self.wfile.write(encoded)
109
-
110
- server = ThreadingHTTPServer((host, actual_port), Handler)
111
- url = f"http://{host}:{actual_port}/"
112
- print(f"{product_name} UI listening on {url}")
113
- if open_browser:
114
- webbrowser.open(url)
115
- try:
116
- server.serve_forever()
117
- except KeyboardInterrupt:
118
- print(f"{product_name} UI stopped")
119
- finally:
120
- server.server_close()
121
- return 0
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import socket
5
+ import webbrowser
6
+ from collections.abc import Callable
7
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
8
+ from typing import Any
9
+ from urllib.parse import urlparse
10
+
11
+ ApiHandler = Callable[[str, str, dict[str, Any] | None], tuple[int, dict[str, Any]]]
12
+
13
+
14
+ def find_available_port(host: str, preferred_port: int, *, attempts: int = 50) -> int:
15
+ start = preferred_port if preferred_port > 0 else 0
16
+ if start == 0:
17
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
18
+ probe.bind((host, 0))
19
+ return int(probe.getsockname()[1])
20
+
21
+ for port in range(start, start + attempts):
22
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as probe:
23
+ probe.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
24
+ try:
25
+ probe.bind((host, port))
26
+ except OSError:
27
+ continue
28
+ return port
29
+ raise OSError(f"No available port found from {preferred_port} to {preferred_port + attempts - 1}")
30
+
31
+
32
+ def serve_dashboard(
33
+ *,
34
+ product_name: str,
35
+ html: str,
36
+ api_handler: ApiHandler,
37
+ host: str,
38
+ port: int,
39
+ open_browser: bool = False,
40
+ api_path_prefixes: tuple[str, ...] = ("/api/",),
41
+ api_exact_paths: tuple[str, ...] = (),
42
+ ) -> int:
43
+ actual_port = find_available_port(host, port)
44
+ exact_paths = set(api_exact_paths)
45
+
46
+ def is_api_path(path: str) -> bool:
47
+ return path in exact_paths or any(path.startswith(prefix) for prefix in api_path_prefixes)
48
+
49
+ class Handler(BaseHTTPRequestHandler):
50
+ server_version = "AbteeXProductUI/0.1"
51
+
52
+ def do_GET(self) -> None: # noqa: N802 - stdlib handler method name
53
+ path = urlparse(self.path).path
54
+ if path == "/":
55
+ self._send_text(200, html, "text/html; charset=utf-8")
56
+ return
57
+ if is_api_path(path):
58
+ self._send_api("GET", path, None)
59
+ return
60
+ self._send_json(404, {"ok": False, "error": "not_found"})
61
+
62
+ def do_POST(self) -> None: # noqa: N802 - stdlib handler method name
63
+ path = urlparse(self.path).path
64
+ if not is_api_path(path):
65
+ self._send_json(404, {"ok": False, "error": "not_found"})
66
+ return
67
+ try:
68
+ length = int(self.headers.get("Content-Length", "0"))
69
+ raw = self.rfile.read(length).decode("utf-8") if length else "{}"
70
+ payload = json.loads(raw)
71
+ if not isinstance(payload, dict):
72
+ raise ValueError("JSON body must be an object")
73
+ self._send_api("POST", path, payload)
74
+ except Exception as exc: # defensive API boundary
75
+ self._send_json(400, {"ok": False, "error": str(exc)})
76
+
77
+ def log_message(self, format: str, *args: Any) -> None: # noqa: A002
78
+ return
79
+
80
+ def _send_api(
81
+ self,
82
+ method: str,
83
+ path: str,
84
+ payload: dict[str, Any] | None,
85
+ ) -> None:
86
+ try:
87
+ status, response = api_handler(method, path, payload)
88
+ except Exception as exc: # defensive API boundary
89
+ status, response = 500, {"ok": False, "error": str(exc)}
90
+ self._send_json(status, response)
91
+
92
+ def _send_json(self, status: int, payload: dict[str, Any]) -> None:
93
+ body = json.dumps(payload, indent=2, sort_keys=True).encode("utf-8")
94
+ self.send_response(status)
95
+ self.send_header("Content-Type", "application/json; charset=utf-8")
96
+ self.send_header("Content-Length", str(len(body)))
97
+ self.send_header("Cache-Control", "no-store")
98
+ self.end_headers()
99
+ self.wfile.write(body)
100
+
101
+ def _send_text(self, status: int, body: str, content_type: str) -> None:
102
+ encoded = body.encode("utf-8")
103
+ self.send_response(status)
104
+ self.send_header("Content-Type", content_type)
105
+ self.send_header("Content-Length", str(len(encoded)))
106
+ self.send_header("Cache-Control", "no-store")
107
+ self.end_headers()
108
+ self.wfile.write(encoded)
109
+
110
+ server = ThreadingHTTPServer((host, actual_port), Handler)
111
+ url = f"http://{host}:{actual_port}/"
112
+ print(f"{product_name} UI listening on {url}")
113
+ if open_browser:
114
+ webbrowser.open(url)
115
+ try:
116
+ server.serve_forever()
117
+ except KeyboardInterrupt:
118
+ print(f"{product_name} UI stopped")
119
+ finally:
120
+ server.server_close()
121
+ return 0
sovereigncode/configs/gateway.local.json CHANGED
@@ -1,13 +1,13 @@
1
- {
2
- "mode": "route_only",
3
- "prompt_retention": "not_stored_by_default",
4
- "default_timeout_seconds": 120,
5
- "backends": {
6
- "example-local-openai-compatible": {
7
- "type": "openai_compatible",
8
- "base_url": "http://127.0.0.1:8000/v1",
9
- "api_key_env": "",
10
- "model": "local-model-id"
11
- }
12
- }
13
- }
 
1
+ {
2
+ "mode": "route_only",
3
+ "prompt_retention": "not_stored_by_default",
4
+ "default_timeout_seconds": 120,
5
+ "backends": {
6
+ "example-local-openai-compatible": {
7
+ "type": "openai_compatible",
8
+ "base_url": "http://127.0.0.1:8000/v1",
9
+ "api_key_env": "",
10
+ "model": "local-model-id"
11
+ }
12
+ }
13
+ }
sovereigncode/configs/service.local.json CHANGED
@@ -1,14 +1,14 @@
1
- {
2
- "ledger_path": ".sovereigncode/audit.jsonl",
3
- "default_region": "NZ",
4
- "fail_closed": true,
5
- "require_human_review_for": [
6
- "write_files",
7
- "execute_shell",
8
- "network_export",
9
- "commit",
10
- "publish",
11
- "train_model"
12
- ],
13
- "marama_route_base_url": "http://127.0.0.1:8787/v1"
14
- }
 
1
+ {
2
+ "ledger_path": ".sovereigncode/audit.jsonl",
3
+ "default_region": "NZ",
4
+ "fail_closed": true,
5
+ "require_human_review_for": [
6
+ "write_files",
7
+ "execute_shell",
8
+ "network_export",
9
+ "commit",
10
+ "publish",
11
+ "train_model"
12
+ ],
13
+ "marama_route_base_url": "http://127.0.0.1:8787/v1"
14
+ }
sovereigncode/ledger.py CHANGED
@@ -1,64 +1,64 @@
1
- from __future__ import annotations
2
-
3
- import hashlib
4
- import json
5
- import threading
6
- from dataclasses import dataclass, field
7
- from datetime import UTC, datetime
8
- from pathlib import Path
9
- from typing import Any
10
-
11
-
12
- def default_ledger_path() -> Path:
13
- return Path.cwd() / ".sovereigncode" / "audit.jsonl"
14
-
15
-
16
- @dataclass(slots=True)
17
- class AuditLedger:
18
- path: Path
19
- _lock: threading.Lock = field(init=False, repr=False)
20
-
21
- def __post_init__(self) -> None:
22
- self._lock = threading.Lock()
23
-
24
- def append(self, event: str, payload: dict[str, Any]) -> dict[str, Any]:
25
- with self._lock:
26
- self.path.parent.mkdir(parents=True, exist_ok=True)
27
- sequence = self._line_count() + 1
28
- record = {
29
- "ledger_sequence": sequence,
30
- "ledger_timestamp": datetime.now(UTC).isoformat(),
31
- "event": event,
32
- "payload": payload,
33
- }
34
- record["ledger_id"] = self._digest(record)
35
- with self.path.open("a", encoding="utf-8", newline="\n") as stream:
36
- stream.write(json.dumps(record, sort_keys=True, separators=(",", ":")))
37
- stream.write("\n")
38
- return {**record, "ledger_path": str(self.path)}
39
-
40
- def tail(self, limit: int = 50) -> list[dict[str, Any]]:
41
- if not self.path.exists():
42
- return []
43
- lines = self.path.read_text(encoding="utf-8-sig").splitlines()
44
- records: list[dict[str, Any]] = []
45
- for line in lines[-max(1, limit) :]:
46
- try:
47
- payload = json.loads(line)
48
- except json.JSONDecodeError:
49
- continue
50
- if isinstance(payload, dict):
51
- payload["ledger_path"] = str(self.path)
52
- records.append(payload)
53
- return records
54
-
55
- def _line_count(self) -> int:
56
- if not self.path.exists():
57
- return 0
58
- with self.path.open("r", encoding="utf-8-sig") as stream:
59
- return sum(1 for line in stream if line.strip())
60
-
61
- @staticmethod
62
- def _digest(record: dict[str, Any]) -> str:
63
- raw = json.dumps(record, sort_keys=True, default=str).encode("utf-8")
64
- return f"sc-ledger-{hashlib.sha256(raw).hexdigest()[:24]}"
 
1
+ from __future__ import annotations
2
+
3
+ import hashlib
4
+ import json
5
+ import threading
6
+ from dataclasses import dataclass, field
7
+ from datetime import UTC, datetime
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+
12
+ def default_ledger_path() -> Path:
13
+ return Path.cwd() / ".sovereigncode" / "audit.jsonl"
14
+
15
+
16
+ @dataclass(slots=True)
17
+ class AuditLedger:
18
+ path: Path
19
+ _lock: threading.Lock = field(init=False, repr=False)
20
+
21
+ def __post_init__(self) -> None:
22
+ self._lock = threading.Lock()
23
+
24
+ def append(self, event: str, payload: dict[str, Any]) -> dict[str, Any]:
25
+ with self._lock:
26
+ self.path.parent.mkdir(parents=True, exist_ok=True)
27
+ sequence = self._line_count() + 1
28
+ record = {
29
+ "ledger_sequence": sequence,
30
+ "ledger_timestamp": datetime.now(UTC).isoformat(),
31
+ "event": event,
32
+ "payload": payload,
33
+ }
34
+ record["ledger_id"] = self._digest(record)
35
+ with self.path.open("a", encoding="utf-8", newline="\n") as stream:
36
+ stream.write(json.dumps(record, sort_keys=True, separators=(",", ":")))
37
+ stream.write("\n")
38
+ return {**record, "ledger_path": str(self.path)}
39
+
40
+ def tail(self, limit: int = 50) -> list[dict[str, Any]]:
41
+ if not self.path.exists():
42
+ return []
43
+ lines = self.path.read_text(encoding="utf-8-sig").splitlines()
44
+ records: list[dict[str, Any]] = []
45
+ for line in lines[-max(1, limit) :]:
46
+ try:
47
+ payload = json.loads(line)
48
+ except json.JSONDecodeError:
49
+ continue
50
+ if isinstance(payload, dict):
51
+ payload["ledger_path"] = str(self.path)
52
+ records.append(payload)
53
+ return records
54
+
55
+ def _line_count(self) -> int:
56
+ if not self.path.exists():
57
+ return 0
58
+ with self.path.open("r", encoding="utf-8-sig") as stream:
59
+ return sum(1 for line in stream if line.strip())
60
+
61
+ @staticmethod
62
+ def _digest(record: dict[str, Any]) -> str:
63
+ raw = json.dumps(record, sort_keys=True, default=str).encode("utf-8")
64
+ return f"sc-ledger-{hashlib.sha256(raw).hexdigest()[:24]}"
sovereigncode/py.typed ADDED
File without changes
sovereigncode/server.py CHANGED
@@ -1,352 +1,352 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import os
5
- import tempfile
6
- from pathlib import Path
7
- from typing import Any
8
-
9
- try: # repo package
10
- from tinyluminax.products._ui_server import serve_dashboard
11
- except ModuleNotFoundError: # standalone HF package
12
- from ._ui_server import serve_dashboard
13
-
14
- try: # repo package
15
- from tinyluminax.products.marama_route import RoutingRequest, load_model_registry
16
- except ModuleNotFoundError: # standalone HF package
17
- from marama_route import RoutingRequest, load_model_registry
18
-
19
- from .audit import build_audit_record
20
- from .ledger import AuditLedger, default_ledger_path
21
- from .planner import plan_coding_turn
22
- from .platform import (
23
- build_capsule_summary,
24
- build_policy_matrix,
25
- build_turn_brief,
26
- check_tool_request,
27
- )
28
- from .policy import DataCapsule, SovereignRequest, SovereigntyPolicyEngine
29
- from .ui import (
30
- PRODUCT_NAME,
31
- build_dashboard_html,
32
- build_dashboard_state,
33
- default_capsule_path,
34
- default_registry_path,
35
- default_request_path,
36
- default_route_request_path,
37
- handle_api_request,
38
- )
39
-
40
-
41
- def handle_service_request(
42
- method: str,
43
- path: str,
44
- payload: dict[str, Any] | None,
45
- *,
46
- capsule_path: Path,
47
- request_path: Path,
48
- route_request_path: Path,
49
- registry_path: Path,
50
- ledger_path: Path,
51
- state: dict[str, Any] | None = None,
52
- ) -> tuple[int, dict[str, Any]]:
53
- ledger = AuditLedger(ledger_path)
54
- service_state = state or build_dashboard_state(capsule_path, request_path, route_request_path, registry_path)
55
-
56
- if path.startswith("/api/"):
57
- return handle_api_request(method, path, payload, registry_path, service_state)
58
- if method == "GET" and path in {"/health", "/v1/health"}:
59
- return 200, _health_payload(ledger, service_state)
60
- if method == "GET" and path == "/v1/audit":
61
- return 200, {"ok": True, "ledger_path": str(ledger.path), "records": ledger.tail()}
62
- if method == "GET" and path == "/v1/capsule-summary":
63
- return 200, {"ok": True, "summary": build_capsule_summary(service_state["capsule"])}
64
- if method == "POST" and path == "/v1/evaluate":
65
- result = evaluate_payload(payload or {}, service_state, ledger)
66
- return (200 if result["decision"]["allowed"] else 422), result
67
- if method == "POST" and path == "/v1/plan-turn":
68
- result = plan_turn_payload(payload or {}, service_state, ledger)
69
- return (200 if result["allowed"] else 422), result
70
- if method == "POST" and path == "/v1/tool-check":
71
- result = tool_check_payload(payload or {}, service_state, ledger)
72
- return (200 if result["ok"] else 422), result
73
- if method == "POST" and path == "/v1/policy-matrix":
74
- return 200, policy_matrix_payload(payload or {}, service_state, ledger)
75
- if method == "POST" and path == "/v1/capsule-summary":
76
- capsule_payload = _mapping(payload, "capsule") or service_state["capsule"]
77
- return 200, {"ok": True, "summary": build_capsule_summary(capsule_payload)}
78
- return 404, {"ok": False, "error": "not_found"}
79
-
80
-
81
- def evaluate_payload(
82
- payload: dict[str, Any],
83
- state: dict[str, Any],
84
- ledger: AuditLedger,
85
- ) -> dict[str, Any]:
86
- capsule = DataCapsule.from_payload(_mapping(payload, "capsule") or state["capsule"])
87
- request = SovereignRequest.from_payload(_mapping(payload, "request") or state["request"])
88
- decision = SovereigntyPolicyEngine().evaluate(capsule, request)
89
- audit = build_audit_record(capsule, request, decision).to_dict()
90
- ledger_record = ledger.append(
91
- "policy_evaluate",
92
- {
93
- "capsule_id": capsule.capsule_id,
94
- "request": request.to_dict(),
95
- "decision": decision.to_dict(),
96
- "audit_record": audit,
97
- },
98
- )
99
- return {
100
- "ok": decision.allowed,
101
- "decision": decision.to_dict(),
102
- "audit_record": audit,
103
- "ledger_record": ledger_record,
104
- }
105
-
106
-
107
- def plan_turn_payload(
108
- payload: dict[str, Any],
109
- state: dict[str, Any],
110
- ledger: AuditLedger,
111
- ) -> dict[str, Any]:
112
- capsule = DataCapsule.from_payload(_mapping(payload, "capsule") or state["capsule"])
113
- request = SovereignRequest.from_payload(_mapping(payload, "request") or state["request"])
114
- route_request = RoutingRequest.from_payload(_mapping(payload, "route_request") or state["route_request"])
115
- models = load_model_registry(Path(str(payload.get("registry_path") or state["registry_path"])))
116
- plan = plan_coding_turn(capsule, request, route_request, models)
117
- result = plan.to_dict()
118
- result["turn_brief"] = build_turn_brief(result)
119
- result["ledger_record"] = ledger.append(
120
- "plan_turn",
121
- {
122
- "capsule_id": capsule.capsule_id,
123
- "allowed": plan.allowed,
124
- "policy_decision": result["policy_decision"],
125
- "route_decision": result["route_decision"],
126
- "audit_record": result["audit_record"],
127
- "turn_brief": result["turn_brief"],
128
- },
129
- )
130
- result["ok"] = plan.allowed
131
- return result
132
-
133
-
134
- def tool_check_payload(
135
- payload: dict[str, Any],
136
- state: dict[str, Any],
137
- ledger: AuditLedger,
138
- ) -> dict[str, Any]:
139
- tool_payload = _mapping(payload, "tool") or {
140
- "tool_name": payload.get("tool_name", "workspace_reader"),
141
- "action": payload.get("action", "read_context"),
142
- "writes_files": bool(payload.get("writes_files", False)),
143
- "exports_data": bool(payload.get("exports_data", False)),
144
- "trains_model": bool(payload.get("trains_model", False)),
145
- "human_approved": bool(payload.get("human_approved", False)),
146
- }
147
- result = check_tool_request(
148
- _mapping(payload, "capsule") or state["capsule"],
149
- _mapping(payload, "request") or state["request"],
150
- tool_payload,
151
- )
152
- result["ledger_record"] = ledger.append(
153
- "tool_check",
154
- {
155
- "tool": tool_payload,
156
- "decision": result["decision"],
157
- "audit_record": result["audit_record"],
158
- "operator_gate": result["operator_gate"],
159
- },
160
- )
161
- return result
162
-
163
-
164
- def policy_matrix_payload(
165
- payload: dict[str, Any],
166
- state: dict[str, Any],
167
- ledger: AuditLedger,
168
- ) -> dict[str, Any]:
169
- scenarios = payload.get("scenarios") if isinstance(payload.get("scenarios"), list) else None
170
- result = build_policy_matrix(
171
- _mapping(payload, "capsule") or state["capsule"],
172
- _mapping(payload, "request") or state["request"],
173
- scenarios,
174
- )
175
- result["ledger_record"] = ledger.append(
176
- "policy_matrix",
177
- {
178
- "capsule_id": result["capsule_id"],
179
- "allowed_count": result["allowed_count"],
180
- "blocked_count": result["blocked_count"],
181
- },
182
- )
183
- return result
184
-
185
-
186
- def smoke_service(
187
- *,
188
- capsule_path: Path | None = None,
189
- request_path: Path | None = None,
190
- route_request_path: Path | None = None,
191
- registry_path: Path | None = None,
192
- ledger_path: Path | None = None,
193
- ) -> dict[str, Any]:
194
- resolved_capsule = capsule_path or default_capsule_path()
195
- resolved_request = request_path or default_request_path()
196
- resolved_route_request = route_request_path or default_route_request_path()
197
- resolved_registry = registry_path or default_registry_path()
198
- resolved_ledger = ledger_path or _temporary_ledger_path()
199
- state = build_dashboard_state(resolved_capsule, resolved_request, resolved_route_request, resolved_registry)
200
-
201
- health_status, health = handle_service_request(
202
- "GET",
203
- "/health",
204
- None,
205
- capsule_path=resolved_capsule,
206
- request_path=resolved_request,
207
- route_request_path=resolved_route_request,
208
- registry_path=resolved_registry,
209
- ledger_path=resolved_ledger,
210
- state=state,
211
- )
212
- evaluate_status, evaluate = handle_service_request(
213
- "POST",
214
- "/v1/evaluate",
215
- {},
216
- capsule_path=resolved_capsule,
217
- request_path=resolved_request,
218
- route_request_path=resolved_route_request,
219
- registry_path=resolved_registry,
220
- ledger_path=resolved_ledger,
221
- state=state,
222
- )
223
- plan_status, plan = handle_service_request(
224
- "POST",
225
- "/v1/plan-turn",
226
- {},
227
- capsule_path=resolved_capsule,
228
- request_path=resolved_request,
229
- route_request_path=resolved_route_request,
230
- registry_path=resolved_registry,
231
- ledger_path=resolved_ledger,
232
- state=state,
233
- )
234
- tool_status, tool = handle_service_request(
235
- "POST",
236
- "/v1/tool-check",
237
- {"tool_name": "workspace_reader", "action": "read_context"},
238
- capsule_path=resolved_capsule,
239
- request_path=resolved_request,
240
- route_request_path=resolved_route_request,
241
- registry_path=resolved_registry,
242
- ledger_path=resolved_ledger,
243
- state=state,
244
- )
245
- audit_status, audit = handle_service_request(
246
- "GET",
247
- "/v1/audit",
248
- None,
249
- capsule_path=resolved_capsule,
250
- request_path=resolved_request,
251
- route_request_path=resolved_route_request,
252
- registry_path=resolved_registry,
253
- ledger_path=resolved_ledger,
254
- state=state,
255
- )
256
-
257
- if (health_status, evaluate_status, plan_status, tool_status, audit_status) != (200, 200, 200, 200, 200):
258
- raise RuntimeError("SovereignCode service smoke failed")
259
- if not evaluate["decision"]["allowed"] or not plan["allowed"] or not tool["ok"]:
260
- raise RuntimeError("SovereignCode service smoke did not allow the governed local request")
261
- return {
262
- "ok": True,
263
- "product": PRODUCT_NAME,
264
- "capsule_id": state["capsule"]["capsule_id"],
265
- "selected_model": plan["turn_brief"]["selected_model"],
266
- "ledger_path": str(resolved_ledger),
267
- "ledger_records": len(audit["records"]),
268
- "tool_next_gate": tool["operator_gate"]["next_gate"],
269
- }
270
-
271
-
272
- def serve_service(
273
- *,
274
- capsule_path: Path | None = None,
275
- request_path: Path | None = None,
276
- route_request_path: Path | None = None,
277
- registry_path: Path | None = None,
278
- ledger_path: Path | None = None,
279
- host: str = "127.0.0.1",
280
- port: int = 8788,
281
- open_browser: bool = False,
282
- smoke: bool = False,
283
- ) -> int:
284
- resolved_capsule = capsule_path or default_capsule_path()
285
- resolved_request = request_path or default_request_path()
286
- resolved_route_request = route_request_path or default_route_request_path()
287
- resolved_registry = registry_path or default_registry_path()
288
- resolved_ledger = ledger_path or default_ledger_path()
289
- if smoke:
290
- print(
291
- json.dumps(
292
- smoke_service(
293
- capsule_path=resolved_capsule,
294
- request_path=resolved_request,
295
- route_request_path=resolved_route_request,
296
- registry_path=resolved_registry,
297
- ledger_path=ledger_path,
298
- ),
299
- indent=2,
300
- sort_keys=True,
301
- ),
302
- )
303
- return 0
304
-
305
- state = build_dashboard_state(resolved_capsule, resolved_request, resolved_route_request, resolved_registry)
306
- html = build_dashboard_html(state)
307
- return serve_dashboard(
308
- product_name=f"{PRODUCT_NAME} Service",
309
- html=html,
310
- api_handler=lambda method, path, request_payload: handle_service_request(
311
- method,
312
- path,
313
- request_payload,
314
- capsule_path=resolved_capsule,
315
- request_path=resolved_request,
316
- route_request_path=resolved_route_request,
317
- registry_path=resolved_registry,
318
- ledger_path=resolved_ledger,
319
- state=state,
320
- ),
321
- host=host,
322
- port=port,
323
- open_browser=open_browser,
324
- api_path_prefixes=("/api/", "/v1/"),
325
- api_exact_paths=("/health",),
326
- )
327
-
328
-
329
- def _health_payload(ledger: AuditLedger, state: dict[str, Any]) -> dict[str, Any]:
330
- return {
331
- "ok": True,
332
- "product": PRODUCT_NAME,
333
- "capsule_id": state["capsule"]["capsule_id"],
334
- "ledger_path": str(ledger.path),
335
- "ledger_records": len(ledger.tail()),
336
- "service": "policy_api_audit_ledger",
337
- }
338
-
339
-
340
- def _mapping(payload: dict[str, Any] | None, key: str) -> dict[str, Any]:
341
- if not isinstance(payload, dict):
342
- return {}
343
- value = payload.get(key)
344
- return dict(value) if isinstance(value, dict) else {}
345
-
346
-
347
- def _temporary_ledger_path() -> Path:
348
- handle, raw_path = tempfile.mkstemp(prefix="sovereigncode-smoke-", suffix=".audit.jsonl")
349
- os.close(handle)
350
- path = Path(raw_path)
351
- path.unlink(missing_ok=True)
352
- return path
 
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import tempfile
6
+ from pathlib import Path
7
+ from typing import Any
8
+
9
+ try: # repo package
10
+ from tinyluminax.products._ui_server import serve_dashboard
11
+ except ModuleNotFoundError: # standalone HF package
12
+ from ._ui_server import serve_dashboard
13
+
14
+ try: # repo package
15
+ from tinyluminax.products.marama_route import RoutingRequest, load_model_registry
16
+ except ModuleNotFoundError: # standalone HF package
17
+ from marama_route import RoutingRequest, load_model_registry
18
+
19
+ from .audit import build_audit_record
20
+ from .ledger import AuditLedger, default_ledger_path
21
+ from .planner import plan_coding_turn
22
+ from .platform import (
23
+ build_capsule_summary,
24
+ build_policy_matrix,
25
+ build_turn_brief,
26
+ check_tool_request,
27
+ )
28
+ from .policy import DataCapsule, SovereignRequest, SovereigntyPolicyEngine
29
+ from .ui import (
30
+ PRODUCT_NAME,
31
+ build_dashboard_html,
32
+ build_dashboard_state,
33
+ default_capsule_path,
34
+ default_registry_path,
35
+ default_request_path,
36
+ default_route_request_path,
37
+ handle_api_request,
38
+ )
39
+
40
+
41
+ def handle_service_request(
42
+ method: str,
43
+ path: str,
44
+ payload: dict[str, Any] | None,
45
+ *,
46
+ capsule_path: Path,
47
+ request_path: Path,
48
+ route_request_path: Path,
49
+ registry_path: Path,
50
+ ledger_path: Path,
51
+ state: dict[str, Any] | None = None,
52
+ ) -> tuple[int, dict[str, Any]]:
53
+ ledger = AuditLedger(ledger_path)
54
+ service_state = state or build_dashboard_state(capsule_path, request_path, route_request_path, registry_path)
55
+
56
+ if path.startswith("/api/"):
57
+ return handle_api_request(method, path, payload, registry_path, service_state)
58
+ if method == "GET" and path in {"/health", "/v1/health"}:
59
+ return 200, _health_payload(ledger, service_state)
60
+ if method == "GET" and path == "/v1/audit":
61
+ return 200, {"ok": True, "ledger_path": str(ledger.path), "records": ledger.tail()}
62
+ if method == "GET" and path == "/v1/capsule-summary":
63
+ return 200, {"ok": True, "summary": build_capsule_summary(service_state["capsule"])}
64
+ if method == "POST" and path == "/v1/evaluate":
65
+ result = evaluate_payload(payload or {}, service_state, ledger)
66
+ return (200 if result["decision"]["allowed"] else 422), result
67
+ if method == "POST" and path == "/v1/plan-turn":
68
+ result = plan_turn_payload(payload or {}, service_state, ledger)
69
+ return (200 if result["allowed"] else 422), result
70
+ if method == "POST" and path == "/v1/tool-check":
71
+ result = tool_check_payload(payload or {}, service_state, ledger)
72
+ return (200 if result["ok"] else 422), result
73
+ if method == "POST" and path == "/v1/policy-matrix":
74
+ return 200, policy_matrix_payload(payload or {}, service_state, ledger)
75
+ if method == "POST" and path == "/v1/capsule-summary":
76
+ capsule_payload = _mapping(payload, "capsule") or service_state["capsule"]
77
+ return 200, {"ok": True, "summary": build_capsule_summary(capsule_payload)}
78
+ return 404, {"ok": False, "error": "not_found"}
79
+
80
+
81
+ def evaluate_payload(
82
+ payload: dict[str, Any],
83
+ state: dict[str, Any],
84
+ ledger: AuditLedger,
85
+ ) -> dict[str, Any]:
86
+ capsule = DataCapsule.from_payload(_mapping(payload, "capsule") or state["capsule"])
87
+ request = SovereignRequest.from_payload(_mapping(payload, "request") or state["request"])
88
+ decision = SovereigntyPolicyEngine().evaluate(capsule, request)
89
+ audit = build_audit_record(capsule, request, decision).to_dict()
90
+ ledger_record = ledger.append(
91
+ "policy_evaluate",
92
+ {
93
+ "capsule_id": capsule.capsule_id,
94
+ "request": request.to_dict(),
95
+ "decision": decision.to_dict(),
96
+ "audit_record": audit,
97
+ },
98
+ )
99
+ return {
100
+ "ok": decision.allowed,
101
+ "decision": decision.to_dict(),
102
+ "audit_record": audit,
103
+ "ledger_record": ledger_record,
104
+ }
105
+
106
+
107
+ def plan_turn_payload(
108
+ payload: dict[str, Any],
109
+ state: dict[str, Any],
110
+ ledger: AuditLedger,
111
+ ) -> dict[str, Any]:
112
+ capsule = DataCapsule.from_payload(_mapping(payload, "capsule") or state["capsule"])
113
+ request = SovereignRequest.from_payload(_mapping(payload, "request") or state["request"])
114
+ route_request = RoutingRequest.from_payload(_mapping(payload, "route_request") or state["route_request"])
115
+ models = load_model_registry(Path(str(payload.get("registry_path") or state["registry_path"])))
116
+ plan = plan_coding_turn(capsule, request, route_request, models)
117
+ result = plan.to_dict()
118
+ result["turn_brief"] = build_turn_brief(result)
119
+ result["ledger_record"] = ledger.append(
120
+ "plan_turn",
121
+ {
122
+ "capsule_id": capsule.capsule_id,
123
+ "allowed": plan.allowed,
124
+ "policy_decision": result["policy_decision"],
125
+ "route_decision": result["route_decision"],
126
+ "audit_record": result["audit_record"],
127
+ "turn_brief": result["turn_brief"],
128
+ },
129
+ )
130
+ result["ok"] = plan.allowed
131
+ return result
132
+
133
+
134
+ def tool_check_payload(
135
+ payload: dict[str, Any],
136
+ state: dict[str, Any],
137
+ ledger: AuditLedger,
138
+ ) -> dict[str, Any]:
139
+ tool_payload = _mapping(payload, "tool") or {
140
+ "tool_name": payload.get("tool_name", "workspace_reader"),
141
+ "action": payload.get("action", "read_context"),
142
+ "writes_files": bool(payload.get("writes_files", False)),
143
+ "exports_data": bool(payload.get("exports_data", False)),
144
+ "trains_model": bool(payload.get("trains_model", False)),
145
+ "human_approved": bool(payload.get("human_approved", False)),
146
+ }
147
+ result = check_tool_request(
148
+ _mapping(payload, "capsule") or state["capsule"],
149
+ _mapping(payload, "request") or state["request"],
150
+ tool_payload,
151
+ )
152
+ result["ledger_record"] = ledger.append(
153
+ "tool_check",
154
+ {
155
+ "tool": tool_payload,
156
+ "decision": result["decision"],
157
+ "audit_record": result["audit_record"],
158
+ "operator_gate": result["operator_gate"],
159
+ },
160
+ )
161
+ return result
162
+
163
+
164
+ def policy_matrix_payload(
165
+ payload: dict[str, Any],
166
+ state: dict[str, Any],
167
+ ledger: AuditLedger,
168
+ ) -> dict[str, Any]:
169
+ scenarios = payload.get("scenarios") if isinstance(payload.get("scenarios"), list) else None
170
+ result = build_policy_matrix(
171
+ _mapping(payload, "capsule") or state["capsule"],
172
+ _mapping(payload, "request") or state["request"],
173
+ scenarios,
174
+ )
175
+ result["ledger_record"] = ledger.append(
176
+ "policy_matrix",
177
+ {
178
+ "capsule_id": result["capsule_id"],
179
+ "allowed_count": result["allowed_count"],
180
+ "blocked_count": result["blocked_count"],
181
+ },
182
+ )
183
+ return result
184
+
185
+
186
+ def smoke_service(
187
+ *,
188
+ capsule_path: Path | None = None,
189
+ request_path: Path | None = None,
190
+ route_request_path: Path | None = None,
191
+ registry_path: Path | None = None,
192
+ ledger_path: Path | None = None,
193
+ ) -> dict[str, Any]:
194
+ resolved_capsule = capsule_path or default_capsule_path()
195
+ resolved_request = request_path or default_request_path()
196
+ resolved_route_request = route_request_path or default_route_request_path()
197
+ resolved_registry = registry_path or default_registry_path()
198
+ resolved_ledger = ledger_path or _temporary_ledger_path()
199
+ state = build_dashboard_state(resolved_capsule, resolved_request, resolved_route_request, resolved_registry)
200
+
201
+ health_status, health = handle_service_request(
202
+ "GET",
203
+ "/health",
204
+ None,
205
+ capsule_path=resolved_capsule,
206
+ request_path=resolved_request,
207
+ route_request_path=resolved_route_request,
208
+ registry_path=resolved_registry,
209
+ ledger_path=resolved_ledger,
210
+ state=state,
211
+ )
212
+ evaluate_status, evaluate = handle_service_request(
213
+ "POST",
214
+ "/v1/evaluate",
215
+ {},
216
+ capsule_path=resolved_capsule,
217
+ request_path=resolved_request,
218
+ route_request_path=resolved_route_request,
219
+ registry_path=resolved_registry,
220
+ ledger_path=resolved_ledger,
221
+ state=state,
222
+ )
223
+ plan_status, plan = handle_service_request(
224
+ "POST",
225
+ "/v1/plan-turn",
226
+ {},
227
+ capsule_path=resolved_capsule,
228
+ request_path=resolved_request,
229
+ route_request_path=resolved_route_request,
230
+ registry_path=resolved_registry,
231
+ ledger_path=resolved_ledger,
232
+ state=state,
233
+ )
234
+ tool_status, tool = handle_service_request(
235
+ "POST",
236
+ "/v1/tool-check",
237
+ {"tool_name": "workspace_reader", "action": "read_context"},
238
+ capsule_path=resolved_capsule,
239
+ request_path=resolved_request,
240
+ route_request_path=resolved_route_request,
241
+ registry_path=resolved_registry,
242
+ ledger_path=resolved_ledger,
243
+ state=state,
244
+ )
245
+ audit_status, audit = handle_service_request(
246
+ "GET",
247
+ "/v1/audit",
248
+ None,
249
+ capsule_path=resolved_capsule,
250
+ request_path=resolved_request,
251
+ route_request_path=resolved_route_request,
252
+ registry_path=resolved_registry,
253
+ ledger_path=resolved_ledger,
254
+ state=state,
255
+ )
256
+
257
+ if (health_status, evaluate_status, plan_status, tool_status, audit_status) != (200, 200, 200, 200, 200):
258
+ raise RuntimeError("SovereignCode service smoke failed")
259
+ if not evaluate["decision"]["allowed"] or not plan["allowed"] or not tool["ok"]:
260
+ raise RuntimeError("SovereignCode service smoke did not allow the governed local request")
261
+ return {
262
+ "ok": True,
263
+ "product": PRODUCT_NAME,
264
+ "capsule_id": state["capsule"]["capsule_id"],
265
+ "selected_model": plan["turn_brief"]["selected_model"],
266
+ "ledger_path": str(resolved_ledger),
267
+ "ledger_records": len(audit["records"]),
268
+ "tool_next_gate": tool["operator_gate"]["next_gate"],
269
+ }
270
+
271
+
272
+ def serve_service(
273
+ *,
274
+ capsule_path: Path | None = None,
275
+ request_path: Path | None = None,
276
+ route_request_path: Path | None = None,
277
+ registry_path: Path | None = None,
278
+ ledger_path: Path | None = None,
279
+ host: str = "127.0.0.1",
280
+ port: int = 8788,
281
+ open_browser: bool = False,
282
+ smoke: bool = False,
283
+ ) -> int:
284
+ resolved_capsule = capsule_path or default_capsule_path()
285
+ resolved_request = request_path or default_request_path()
286
+ resolved_route_request = route_request_path or default_route_request_path()
287
+ resolved_registry = registry_path or default_registry_path()
288
+ resolved_ledger = ledger_path or default_ledger_path()
289
+ if smoke:
290
+ print(
291
+ json.dumps(
292
+ smoke_service(
293
+ capsule_path=resolved_capsule,
294
+ request_path=resolved_request,
295
+ route_request_path=resolved_route_request,
296
+ registry_path=resolved_registry,
297
+ ledger_path=ledger_path,
298
+ ),
299
+ indent=2,
300
+ sort_keys=True,
301
+ ),
302
+ )
303
+ return 0
304
+
305
+ state = build_dashboard_state(resolved_capsule, resolved_request, resolved_route_request, resolved_registry)
306
+ html = build_dashboard_html(state)
307
+ return serve_dashboard(
308
+ product_name=f"{PRODUCT_NAME} Service",
309
+ html=html,
310
+ api_handler=lambda method, path, request_payload: handle_service_request(
311
+ method,
312
+ path,
313
+ request_payload,
314
+ capsule_path=resolved_capsule,
315
+ request_path=resolved_request,
316
+ route_request_path=resolved_route_request,
317
+ registry_path=resolved_registry,
318
+ ledger_path=resolved_ledger,
319
+ state=state,
320
+ ),
321
+ host=host,
322
+ port=port,
323
+ open_browser=open_browser,
324
+ api_path_prefixes=("/api/", "/v1/"),
325
+ api_exact_paths=("/health",),
326
+ )
327
+
328
+
329
+ def _health_payload(ledger: AuditLedger, state: dict[str, Any]) -> dict[str, Any]:
330
+ return {
331
+ "ok": True,
332
+ "product": PRODUCT_NAME,
333
+ "capsule_id": state["capsule"]["capsule_id"],
334
+ "ledger_path": str(ledger.path),
335
+ "ledger_records": len(ledger.tail()),
336
+ "service": "policy_api_audit_ledger",
337
+ }
338
+
339
+
340
+ def _mapping(payload: dict[str, Any] | None, key: str) -> dict[str, Any]:
341
+ if not isinstance(payload, dict):
342
+ return {}
343
+ value = payload.get(key)
344
+ return dict(value) if isinstance(value, dict) else {}
345
+
346
+
347
+ def _temporary_ledger_path() -> Path:
348
+ handle, raw_path = tempfile.mkstemp(prefix="sovereigncode-smoke-", suffix=".audit.jsonl")
349
+ os.close(handle)
350
+ path = Path(raw_path)
351
+ path.unlink(missing_ok=True)
352
+ return path