build(agent): molt-a#3856f9 iteration

This commit is contained in:
agent-3856f9f6ac3cbf34 2026-04-15 01:43:58 +02:00
parent 3a399dbbb2
commit ff8ab1f321
4 changed files with 103 additions and 0 deletions

View File

@ -14,6 +14,12 @@ How to run tests
- Run: `./test.sh` - Run: `./test.sh`
- This will execute unit tests and verify packaging with `python -m build`. - This will execute unit tests and verify packaging with `python -m build`.
MVP extensions (planned, small scope)
- Add a minimal DSL (nova_plan.dsl) and a delta-synchronization helper (delta_sync) to scaffold federated optimization flows.
- Introduce a lightweight ContractRegistry to enable versioning and interoperability of data contracts.
- Provide a tiny DSL-to-LocalProblem translator to bootstrap CatOpt-style integration with adapters.
- Expand ledger anchoring with a deterministic reconciliation log for outages.
Directory layout Directory layout
- nova_plan/ Core MVP implementation (planner, contracts, ledger, adapters) - nova_plan/ Core MVP implementation (planner, contracts, ledger, adapters)
- tests/ Unit tests for core workflow and contracts - tests/ Unit tests for core workflow and contracts

View File

@ -47,3 +47,15 @@ def serialize(obj: object) -> str:
if hasattr(obj, "__dict__"): if hasattr(obj, "__dict__"):
return json.dumps(obj.__dict__) return json.dumps(obj.__dict__)
return json.dumps(obj) return json.dumps(obj)
# Lightweight contract registry for versioning and interoperability
class ContractRegistry:
_registry: Dict[str, int] = {}
@classmethod
def register(cls, name: str, version: int) -> None:
cls._registry[name] = int(version)
@classmethod
def version_of(cls, name: str, default: int | None = None) -> int | None:
return cls._registry.get(name, default)

62
nova_plan/dsl.py Normal file
View File

@ -0,0 +1,62 @@
"""Minimal NovaPlan DSL scaffolding.
This module provides a tiny domain-specific language (DSL) abstraction
to express a local planning problem in a serialized form, which can be
translated into the existing LocalProblem used by the MVP tests.
The DSL is intentionally lightweight and deterministic to keep tests fast
and comprehensible. It is not meant to be a full-featured language yet.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Dict, Any, Callable, Optional
import time
from nova_plan.planner import LocalProblem
from nova_plan.contracts import PlanDelta
@dataclass
class LocalProblemDSL:
"""A minimal serializable description of a local problem.
This captures a simple objective expressed as a Python expression string
that will be evaluated in a safe environment at runtime. The expression
should reference `vars` for local variables and `shared` for shared ones,
for example: "(vars['x'] - shared['x'])**2".
"""
agent_id: str
objective_expr: str
variables: Dict[str, float]
constraints: Optional[Dict[str, Any]] = None
def to_local_problem(self) -> LocalProblem:
"""Convert to a LocalProblem instance.
The evaluation environment is intentionally restricted to avoid
executing arbitrary code. Support for richer DSLs can be added later.
"""
def _objective(local_vars: Dict[str, float], shared: Dict[str, float]) -> float:
# Provide a lightweight evaluation context.
ctx = {
"vars": local_vars,
"shared": shared,
}
# Intentionally restrict builtins to avoid dangerous calls.
safe_builtins = {"min": min, "max": max, "abs": abs}
return float(eval(self.objective_expr, {"__builtins__": safe_builtins}, ctx))
return LocalProblem(
id=self.agent_id,
objective=_objective,
variables=self.variables.copy(),
constraints=(self.constraints or {}),
)
def to_plan_delta(self, delta: Dict[str, float], timestamp: Optional[float] = None) -> PlanDelta:
"""Create a PlanDelta from this DSL with a given delta map."""
import time as _time
return PlanDelta(agent_id=self.agent_id, delta=delta, timestamp=timestamp or _time.time())

View File

@ -6,6 +6,8 @@ is intentionally small and deterministic to enable unit tests and demonstrations
""" """
from __future__ import annotations from __future__ import annotations
from typing import Dict, Any from typing import Dict, Any
import time
from nova_plan.contracts import PlanDelta
class LocalProblem: class LocalProblem:
"""A tiny local optimization problem. """A tiny local optimization problem.
@ -39,3 +41,24 @@ def simple_admm_step(local: LocalProblem, shared_vars: Dict[str, float], rho: fl
new_vars[k] = v + rho * (s - v) new_vars[k] = v + rho * (s - v)
local.variables = new_vars local.variables = new_vars
return new_vars return new_vars
def delta_sync(local: LocalProblem, shared_vars: Dict[str, float], agent_id: str | None = None, rho: float = 1.0) -> PlanDelta:
"""Create a PlanDelta representing the current local delta with shared_vars.
This is a lightweight helper to bootstrap delta exchange between agents
in an ADMM-like loop. It mirrors the minimal API used by tests and MVP
demos, returning a serializable PlanDelta.
"""
delta = {}
for k, v in local.variables.items():
s = shared_vars.get(k, 0.0)
delta[k] = v - s
# Optionally, we could apply a small adjustment here using rho if desired.
local_val = local.variables.get(k, 0.0)
shared_val = shared_vars.get(k, 0.0)
# Apply a tiny step toward the shared value to reflect a one-pass update.
local.variables[k] = local_val + rho * (shared_val - local_val)
# Build PlanDelta for governance/traceability
ts = time.time()
return PlanDelta(agent_id=agent_id or getattr(local, "id", "unknown"), delta=delta, timestamp=ts)