build(agent): weasel-1#856f80 iteration
This commit is contained in:
parent
e66cc61623
commit
850e4b5f91
21
README.md
21
README.md
|
|
@ -1,16 +1,11 @@
|
||||||
# EdgeMind - Verifiable Onboard IR (initial skeleton)
|
# EdgeMind EnergiBridge IR (Schemas)
|
||||||
|
|
||||||
This repository contains an initial Python skeleton for the EdgeMind IR (Intermediate Representation) and a small set of Pydantic models representing the canonical IR types used by the EnergiBridge and EdgeMind runtime.
|
This package contains Pydantic models and example JSON/YAML specs for the EnergiBridge canonical interop IR described in the EdgeMind idea: LocalProblem, SharedSignals, PlanDelta, SafetyContract, AuditLog, and AdapterContract.
|
||||||
|
|
||||||
What is included in this change:
|
What this commit provides:
|
||||||
- pyproject.toml with packaging metadata and dependency on pydantic
|
- Python package `edgemind` with Pydantic models.
|
||||||
- specs/ir.py: Pydantic models for LocalProblem, SharedSignals, PlanDelta, SafetyContract, AuditLog, AdapterContract
|
- Example YAML specs in `/specs`.
|
||||||
- tests/test_ir_models.py: unit tests that validate model instantiation and JSON schema generation
|
- Unit tests that validate model construction and serialization.
|
||||||
- test.sh: convenience script to run tests and build
|
- `test.sh` which runs `pytest` and `python3 -m build` to verify packaging.
|
||||||
|
|
||||||
How to run tests and build (also invoked by the CI harness):
|
Next steps for contributors: implement adapters, delta-sync engine, and runtime enforcement components.
|
||||||
|
|
||||||
bash test.sh
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
- This is a focused, well-scoped first chunk of the overall EdgeMind idea: it provides canonical, typed IR models and tests that the models behave and can produce JSON Schema. Next steps would be to export JSON Schema files, implement adapter skeletons, and add delta-sync/planner pieces.
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
"""EdgeMind EnergiBridge IR package"""
|
||||||
|
__all__ = [
|
||||||
|
"schema",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,67 @@
|
||||||
|
from typing import Dict, List, Optional, Any
|
||||||
|
from pydantic import BaseModel, Field, validator
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
class SafetyContract(BaseModel):
|
||||||
|
id: str
|
||||||
|
description: Optional[str]
|
||||||
|
# Predicate expressed as a simple string (to evaluate in a sandboxed evaluator later)
|
||||||
|
predicate: str
|
||||||
|
fail_safe: Optional[str] = Field(
|
||||||
|
default="halt", description="Action to take on violation: halt|safe-mode|notify"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LocalProblem(BaseModel):
|
||||||
|
id: str
|
||||||
|
goal_type: str
|
||||||
|
state_vars: Dict[str, Any]
|
||||||
|
hard_constraints: Optional[List[str]] = None
|
||||||
|
soft_costs: Optional[Dict[str, float]] = None
|
||||||
|
energy_budget: Optional[float] = None
|
||||||
|
time_window: Optional[Dict[str, str]] = None
|
||||||
|
actuator_interface: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
|
class SharedSignal(BaseModel):
|
||||||
|
name: str
|
||||||
|
# renamed from `schema` to avoid colliding with BaseModel.schema()
|
||||||
|
signal_schema: Dict[str, Any]
|
||||||
|
privacy_budget: Optional[float] = None
|
||||||
|
|
||||||
|
|
||||||
|
class PlanDelta(BaseModel):
|
||||||
|
id: str
|
||||||
|
base_plan_id: Optional[str]
|
||||||
|
patches: List[Dict[str, Any]]
|
||||||
|
timestamp: datetime
|
||||||
|
safety_tags: Optional[List[str]] = None
|
||||||
|
|
||||||
|
|
||||||
|
class AuditLog(BaseModel):
|
||||||
|
entry_id: str
|
||||||
|
timestamp: datetime
|
||||||
|
actor: str
|
||||||
|
action: str
|
||||||
|
metadata: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
|
||||||
|
class AdapterContract(BaseModel):
|
||||||
|
adapter_id: str
|
||||||
|
supported_domains: List[str]
|
||||||
|
contract_version: str
|
||||||
|
metadata: Optional[Dict[str, Any]] = None
|
||||||
|
|
||||||
|
|
||||||
|
class EnergiBridgeIR(BaseModel):
|
||||||
|
local_problem: Optional[LocalProblem] = None
|
||||||
|
shared_signals: Optional[List[SharedSignal]] = None
|
||||||
|
plan_delta: Optional[PlanDelta] = None
|
||||||
|
safety_contracts: Optional[List[SafetyContract]] = None
|
||||||
|
audit_logs: Optional[List[AuditLog]] = None
|
||||||
|
adapter: Optional[AdapterContract] = None
|
||||||
|
|
||||||
|
@validator("shared_signals", pre=True, always=True)
|
||||||
|
def ensure_list(cls, v):
|
||||||
|
return v or []
|
||||||
|
|
@ -1,16 +1,3 @@
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["setuptools>=40.8.0", "wheel"]
|
requires = ["setuptools>=42", "wheel"]
|
||||||
build-backend = "setuptools.build_meta"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "edgemind-verifiable-onboard"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "EdgeMind: Verifiable Onboard AI Planning Runtime (IR schema + small spec)"
|
|
||||||
readme = "README.md"
|
|
||||||
requires-python = ">=3.8"
|
|
||||||
dependencies = [
|
|
||||||
"pydantic>=1.10",
|
|
||||||
]
|
|
||||||
|
|
||||||
[tool.setuptools.packages.find]
|
|
||||||
where = ["."]
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
[metadata]
|
||||||
|
name = edgemind
|
||||||
|
version = 0.1.0
|
||||||
|
description = EdgeMind EnergiBridge IR schemas and tools
|
||||||
|
long_description = file: README.md
|
||||||
|
long_description_content_type = text/markdown
|
||||||
|
author = EdgeMind Contributors
|
||||||
|
license = MIT
|
||||||
|
|
||||||
|
[options]
|
||||||
|
packages = find:
|
||||||
|
install_requires =
|
||||||
|
pydantic>=1.10
|
||||||
|
PyYAML>=6.0
|
||||||
|
|
||||||
|
[options.packages.find]
|
||||||
|
where = .
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
adapter_id: adapter_ros2_sensor_gateway
|
||||||
|
supported_domains:
|
||||||
|
- mobility
|
||||||
|
- perception
|
||||||
|
contract_version: "0.1.0"
|
||||||
|
metadata:
|
||||||
|
tls: required
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
id: local_problem_001
|
||||||
|
goal_type: energy_aware_path
|
||||||
|
state_vars:
|
||||||
|
start: {x: 0, y: 0}
|
||||||
|
goal: {x: 10, y: 2}
|
||||||
|
hard_constraints:
|
||||||
|
- "avoid_obstacles"
|
||||||
|
soft_costs:
|
||||||
|
time: 1.0
|
||||||
|
energy: 5.0
|
||||||
|
energy_budget: 100.0
|
||||||
|
time_window:
|
||||||
|
start: "2026-01-01T00:00:00Z"
|
||||||
|
end: "2026-01-01T01:00:00Z"
|
||||||
|
actuator_interface: ros2_motion_controller
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
id: sc_001
|
||||||
|
description: "Battery must not fall below 10% during maneuver"
|
||||||
|
predicate: "battery_level >= 0.10"
|
||||||
|
fail_safe: safe-mode
|
||||||
8
test.sh
8
test.sh
|
|
@ -1,10 +1,8 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
echo "Running unit tests..."
|
||||||
echo "Running pytest..."
|
export PYTHONPATH="$(pwd)"
|
||||||
pytest -q
|
pytest -q
|
||||||
|
echo "Running build verification..."
|
||||||
echo "Building package to verify pyproject metadata..."
|
|
||||||
python3 -m build
|
python3 -m build
|
||||||
|
|
||||||
echo "All checks passed."
|
echo "All checks passed."
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
import yaml
|
||||||
|
from edgemind import schema
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
|
def test_local_problem_from_yaml():
|
||||||
|
with open("specs/LocalProblem.example.yaml", "r") as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
lp = schema.LocalProblem(**data)
|
||||||
|
assert lp.id == "local_problem_001"
|
||||||
|
assert lp.goal_type == "energy_aware_path"
|
||||||
|
|
||||||
|
|
||||||
|
def test_safety_contract_from_yaml():
|
||||||
|
with open("specs/SafetyContract.example.yaml", "r") as f:
|
||||||
|
data = yaml.safe_load(f)
|
||||||
|
sc = schema.SafetyContract(**data)
|
||||||
|
assert sc.predicate == "battery_level >= 0.10"
|
||||||
|
|
||||||
|
|
||||||
|
def test_plan_delta_and_auditlog():
|
||||||
|
now = datetime.utcnow()
|
||||||
|
pd = schema.PlanDelta(
|
||||||
|
id="pd1",
|
||||||
|
base_plan_id=None,
|
||||||
|
patches=[{"op": "replace", "path": "/plan/steps/0", "value": {}}],
|
||||||
|
timestamp=now,
|
||||||
|
)
|
||||||
|
al = schema.AuditLog(entry_id="a1", timestamp=now, actor="tester", action="create", metadata={})
|
||||||
|
ir = schema.EnergiBridgeIR(local_problem=None, plan_delta=pd, audit_logs=[al])
|
||||||
|
assert ir.plan_delta.id == "pd1"
|
||||||
|
assert ir.audit_logs[0].actor == "tester"
|
||||||
Loading…
Reference in New Issue