Files
JspaceAI/jspaceai/events.py
XiuchengWu 300e86956b Implement consensus and memory management for workspace events
- Add ConsensusSnapshot and ConsensusSlot classes for structured consensus state representation.
- Introduce OnlineLanguageLearner for stateful online learning with experience replay and EWC regularization.
- Create WorkspaceEvent and ActionEvent classes for serializable event types.
- Develop InMemoryVectorMemoryStore for storing and querying workspace events.
- Implement ActionPolicy to manage action selection and motor parameterization.
- Establish a unified WorkspaceRuntime for managing the agent's lifecycle and interactions.
- Enhance tests in test_smoke.py to cover new functionalities and ensure correctness.
2026-07-08 12:24:26 +08:00

129 lines
3.7 KiB
Python

"""
Serializable event types for the workspace-centered runtime.
These data packets are intentionally small and plain. They give local modules,
future worker processes, and external transports the same language for passing
workspace state around without sharing live Python objects.
"""
from __future__ import annotations
from dataclasses import dataclass, field
import time
from typing import Any
import numpy as np
import torch
from .consensus import ConsensusSnapshot
def _workspace_vector(w: torch.Tensor | np.ndarray | list[float]) -> list[float]:
if isinstance(w, torch.Tensor):
data = w.detach().cpu()
if data.dim() > 1:
data = data[0]
return data.reshape(-1).tolist()
if isinstance(w, np.ndarray):
data = w
if data.ndim > 1:
data = data[0]
return data.reshape(-1).astype(float).tolist()
return [float(v) for v in w]
def _consensus_dict(consensus: ConsensusSnapshot | dict | None) -> dict | None:
if consensus is None:
return None
if isinstance(consensus, ConsensusSnapshot):
return consensus.to_dict()
return consensus
@dataclass
class WorkspaceEvent:
"""A transport-friendly snapshot of workspace state."""
step: int
modality: str
workspace: list[float]
consensus: dict | None = None
context: dict[str, Any] = field(default_factory=dict)
timestamp: float = field(default_factory=time.time)
kind: str = "workspace"
@classmethod
def from_tensor(
cls,
w: torch.Tensor | np.ndarray | list[float],
modality: str,
step: int = 0,
consensus: ConsensusSnapshot | dict | None = None,
context: dict | None = None,
) -> "WorkspaceEvent":
return cls(
step=step,
modality=modality,
workspace=_workspace_vector(w),
consensus=_consensus_dict(consensus),
context=context or {},
)
def workspace_array(self) -> np.ndarray:
return np.asarray(self.workspace, dtype=np.float32)
def to_dict(self) -> dict:
return {
"kind": self.kind,
"step": self.step,
"modality": self.modality,
"workspace": list(self.workspace),
"consensus": self.consensus,
"context": self.context,
"timestamp": self.timestamp,
}
@dataclass
class ActionEvent:
"""A transport-friendly action decision/result."""
step: int
action_idx: int
action_name: str
action_params: list[float]
executed: bool
risk: float = 0.0
context: dict[str, Any] = field(default_factory=dict)
timestamp: float = field(default_factory=time.time)
kind: str = "action"
@classmethod
def from_action_info(
cls,
action_info: dict,
step: int = 0,
context: dict | None = None,
) -> "ActionEvent":
return cls(
step=step,
action_idx=int(action_info.get("action_idx", 0)),
action_name=str(action_info.get("action_name", "observe")),
action_params=[float(v) for v in action_info.get("action_params", [])],
executed=bool(action_info.get("executed", False)),
risk=float(action_info.get("risk", 0.0)),
context=context or {},
)
def to_dict(self) -> dict:
return {
"kind": self.kind,
"step": self.step,
"action_idx": self.action_idx,
"action_name": self.action_name,
"action_params": list(self.action_params),
"executed": self.executed,
"risk": self.risk,
"context": self.context,
"timestamp": self.timestamp,
}