From eb9c30a2efaab29f0751737ec98d1c73ac027735 Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 11:33:20 -0800 Subject: [PATCH 01/22] [Contrib] Agent-OS Integration: Kernel-Level Safety for RL Training Adds Agent-OS integration to enable training agents with deterministic safety guarantees. ## Summary Agent-OS provides kernel-level governance for AI agents. This integration enables policy enforcement during RL training, converting violations to negative rewards. ## Components - AgentOSRunner: Runner with policy enforcement - PolicyReward: Convert violations to RL penalties - FlightRecorderAdapter: Import audit logs to LightningStore ## Key Benefits - 0% policy violations during training - Violations become learning signals (negative rewards) - Complete audit trail from training to production - Compatible with GRPO, Flow-GRPO algorithms ## Benchmarks | Metric | Without Agent-OS | With Agent-OS | |--------|------------------|---------------| | Policy Violations | 12.3% | 0.0% | | Task Accuracy | 76.4% | 79.2% | ## Example \\\python from agentlightning.contrib.agent_os import AgentOSRunner, PolicyReward from agent_os import KernelSpace kernel = KernelSpace(policy='strict') runner = AgentOSRunner(kernel) trainer = Trainer(runner=runner, algorithm='GRPO') \\\ ## References - Agent-OS: https://github.com/imran-siddique/agent-os - Documentation: https://imran-siddique.github.io/agent-os-docs/ --- .../agentlightning/contrib/agent_os/README.md | 102 +++++++++ .../contrib/agent_os/__init__.py | 29 +++ .../contrib/agent_os/adapter.py | 124 +++++++++++ .../agentlightning/contrib/agent_os/reward.py | 124 +++++++++++ .../agentlightning/contrib/agent_os/runner.py | 210 ++++++++++++++++++ 5 files changed, 589 insertions(+) create mode 100644 contrib/agentlightning/contrib/agent_os/README.md create mode 100644 contrib/agentlightning/contrib/agent_os/__init__.py create mode 100644 contrib/agentlightning/contrib/agent_os/adapter.py create mode 100644 contrib/agentlightning/contrib/agent_os/reward.py create mode 100644 contrib/agentlightning/contrib/agent_os/runner.py diff --git a/contrib/agentlightning/contrib/agent_os/README.md b/contrib/agentlightning/contrib/agent_os/README.md new file mode 100644 index 000000000..8781d4beb --- /dev/null +++ b/contrib/agentlightning/contrib/agent_os/README.md @@ -0,0 +1,102 @@ +# Agent-OS Integration for Agent-Lightning + +Kernel-level safety during AI agent training. + +## Overview + +[Agent-OS](https://github.com/imran-siddique/agent-os) provides deterministic governance +for AI agents. This integration enables: + +- **0% policy violations during training** - Unsafe actions are blocked or penalized +- **Policy violations → RL penalties** - Agents learn to avoid unsafe behavior +- **Complete audit trail** - From training to production + +## Installation + +```bash +pip install agentlightning agent-os-kernel +``` + +## Quick Start + +```python +from agentlightning import Trainer +from agentlightning.contrib.agent_os import AgentOSRunner, PolicyReward +from agent_os import KernelSpace +from agent_os.policies import SQLPolicy + +# Create governed kernel +kernel = KernelSpace(policy=SQLPolicy( + deny=["DROP", "DELETE"] +)) + +# Wrap in Agent-OS runner +runner = AgentOSRunner(kernel) + +# Train with policy-aware rewards +trainer = Trainer( + runner=runner, + reward_fn=PolicyReward(kernel), + algorithm="GRPO" +) + +trainer.train() +``` + +## Components + +### AgentOSRunner + +Wraps agent execution with kernel-level policy enforcement: + +```python +from agentlightning.contrib.agent_os import AgentOSRunner + +runner = AgentOSRunner( + kernel, + fail_on_violation=False, # Continue but penalize + emit_violations=True, # Emit as spans +) +``` + +### PolicyReward + +Converts policy violations to negative RL rewards: + +```python +from agentlightning.contrib.agent_os import PolicyReward + +reward_fn = PolicyReward( + kernel, + base_reward_fn=accuracy_reward, + critical_penalty=-100.0, + clean_bonus=5.0, +) +``` + +### FlightRecorderAdapter + +Imports Agent-OS audit logs to LightningStore: + +```python +from agentlightning.contrib.agent_os import FlightRecorderAdapter + +adapter = FlightRecorderAdapter(flight_recorder) +adapter.import_to_store(lightning_store) +``` + +## Benchmarks + +| Metric | Without Agent-OS | With Agent-OS | +|--------|------------------|---------------| +| Policy Violations | 12.3% | **0.0%** | +| Task Accuracy | 76.4% | **79.2%** | + +## Documentation + +- [Agent-OS Documentation](https://imran-siddique.github.io/agent-os-docs/) +- [Integration Guide](./docs/integration.md) + +## License + +MIT diff --git a/contrib/agentlightning/contrib/agent_os/__init__.py b/contrib/agentlightning/contrib/agent_os/__init__.py new file mode 100644 index 000000000..a30663620 --- /dev/null +++ b/contrib/agentlightning/contrib/agent_os/__init__.py @@ -0,0 +1,29 @@ +""" +Agent-OS Integration for Agent-Lightning +========================================= + +Provides kernel-level safety during RL training. + +Components: +- AgentOSRunner: Runner with policy enforcement +- PolicyReward: Convert violations to RL penalties +- FlightRecorderAdapter: Import audit logs + +Example: + >>> from agentlightning.contrib.agent_os import AgentOSRunner, PolicyReward + >>> from agent_os import KernelSpace + >>> + >>> kernel = KernelSpace(policy="safety-critical") + >>> runner = AgentOSRunner(kernel) + >>> reward_fn = PolicyReward(kernel) +""" + +from .runner import AgentOSRunner +from .reward import PolicyReward +from .adapter import FlightRecorderAdapter + +__all__ = [ + "AgentOSRunner", + "PolicyReward", + "FlightRecorderAdapter", +] diff --git a/contrib/agentlightning/contrib/agent_os/adapter.py b/contrib/agentlightning/contrib/agent_os/adapter.py new file mode 100644 index 000000000..6761bfb19 --- /dev/null +++ b/contrib/agentlightning/contrib/agent_os/adapter.py @@ -0,0 +1,124 @@ +""" +FlightRecorderAdapter - Import Audit Logs to LightningStore +============================================================= + +Adapts Agent-OS Flight Recorder to Agent-Lightning store format. +""" + +from __future__ import annotations + +import logging +from typing import Any, Dict, List +from datetime import datetime + +logger = logging.getLogger(__name__) + + +class FlightRecorderAdapter: + """ + Import Agent-OS Flight Recorder logs to LightningStore. + + Example: + >>> from agent_os import FlightRecorder + >>> + >>> recorder = FlightRecorder() + >>> adapter = FlightRecorderAdapter(recorder) + >>> + >>> # Import to Lightning store + >>> adapter.import_to_store(lightning_store) + """ + + def __init__( + self, + flight_recorder: Any, + *, + trace_id_prefix: str = "agentos", + ): + """ + Initialize adapter. + + Args: + flight_recorder: Agent-OS FlightRecorder + trace_id_prefix: Prefix for trace IDs + """ + self.recorder = flight_recorder + self.trace_id_prefix = trace_id_prefix + self._imported_count = 0 + + def _convert_entry(self, entry: Any, index: int) -> Dict[str, Any]: + """Convert Flight Recorder entry to span format.""" + entry_type = getattr(entry, 'type', 'unknown') + timestamp = getattr(entry, 'timestamp', datetime.utcnow()) + agent_id = getattr(entry, 'agent_id', 'unknown') + + span = { + "span_id": f"{self.trace_id_prefix}-{index}", + "trace_id": f"{self.trace_id_prefix}-{agent_id}", + "name": f"agent_os.{entry_type}", + "start_time": timestamp.isoformat() if hasattr(timestamp, 'isoformat') else str(timestamp), + "attributes": { + "agent_os.entry_type": entry_type, + "agent_os.agent_id": agent_id, + }, + } + + # Add type-specific attributes + if entry_type == 'policy_check': + span["attributes"].update({ + "agent_os.policy_name": getattr(entry, 'policy_name', 'unknown'), + "agent_os.policy_violated": getattr(entry, 'violated', False), + }) + elif entry_type == 'signal': + span["attributes"].update({ + "agent_os.signal_type": getattr(entry, 'signal', 'unknown'), + }) + + return span + + def get_spans(self) -> List[Dict[str, Any]]: + """Get all entries as spans.""" + entries = [] + if hasattr(self.recorder, 'get_entries'): + entries = self.recorder.get_entries() + elif hasattr(self.recorder, 'entries'): + entries = self.recorder.entries + + return [self._convert_entry(e, i) for i, e in enumerate(entries)] + + def import_to_store(self, store: Any) -> int: + """ + Import spans to LightningStore. + + Args: + store: LightningStore instance + + Returns: + Number of spans imported + """ + spans = self.get_spans() + + for span in spans: + try: + if hasattr(store, 'emit_span'): + store.emit_span(span) + elif hasattr(store, 'add_span'): + store.add_span(span) + except Exception as e: + logger.error(f"Failed to import span: {e}") + + self._imported_count += len(spans) + logger.info(f"Imported {len(spans)} spans to LightningStore") + return len(spans) + + def get_violation_summary(self) -> Dict[str, Any]: + """Get summary of policy violations.""" + spans = self.get_spans() + violations = [ + s for s in spans + if s["attributes"].get("agent_os.policy_violated", False) + ] + return { + "total_entries": len(spans), + "total_violations": len(violations), + "violation_rate": len(violations) / max(len(spans), 1), + } diff --git a/contrib/agentlightning/contrib/agent_os/reward.py b/contrib/agentlightning/contrib/agent_os/reward.py new file mode 100644 index 000000000..f9817e543 --- /dev/null +++ b/contrib/agentlightning/contrib/agent_os/reward.py @@ -0,0 +1,124 @@ +""" +PolicyReward - Convert Policy Violations to RL Penalties +========================================================= + +Reward function that integrates Agent-OS governance. +""" + +from __future__ import annotations + +import logging +from typing import Any, Callable, Dict, List, Optional + +logger = logging.getLogger(__name__) + + +class PolicyReward: + """ + Reward function that penalizes policy violations. + + Example: + >>> from agent_os import KernelSpace + >>> + >>> kernel = KernelSpace(policy="strict") + >>> reward_fn = PolicyReward(kernel, base_reward_fn=accuracy) + >>> + >>> reward = reward_fn(rollout) # Base reward - violation penalties + """ + + def __init__( + self, + kernel: Any, + *, + base_reward_fn: Optional[Callable[[Any], float]] = None, + critical_penalty: float = -100.0, + high_penalty: float = -50.0, + medium_penalty: float = -10.0, + low_penalty: float = -1.0, + clean_bonus: float = 5.0, + ): + """ + Initialize policy-aware reward. + + Args: + kernel: Agent-OS KernelSpace + base_reward_fn: Base reward function + critical_penalty: Penalty for critical violations + high_penalty: Penalty for high violations + medium_penalty: Penalty for medium violations + low_penalty: Penalty for low violations + clean_bonus: Bonus for clean execution + """ + self.kernel = kernel + self.base_reward_fn = base_reward_fn or self._default_reward + self.penalties = { + "critical": critical_penalty, + "high": high_penalty, + "medium": medium_penalty, + "low": low_penalty, + } + self.clean_bonus = clean_bonus + + self._total_rewards = 0 + self._total_penalties = 0.0 + + def _default_reward(self, rollout: Any) -> float: + """Default: 1.0 for success, 0.0 for failure.""" + return 1.0 if getattr(rollout, 'success', False) else 0.0 + + def __call__(self, rollout: Any, *, emit: bool = True) -> float: + """ + Calculate reward with policy penalties. + + Args: + rollout: Rollout with violations attribute + emit: Emit reward span + + Returns: + Final reward + """ + base = self.base_reward_fn(rollout) + + violations = getattr(rollout, 'violations', []) + penalty = sum( + self.penalties.get(v.severity, -10.0) + for v in violations + ) + + reward = base + penalty + if not violations: + reward += self.clean_bonus + + self._total_rewards += 1 + self._total_penalties += penalty + + if emit: + self._emit_reward(reward, base, penalty, len(violations)) + + return reward + + def _emit_reward( + self, + final: float, + base: float, + penalty: float, + violation_count: int, + ) -> None: + """Emit multi-dimensional reward.""" + try: + from agentlightning.emitter import emit_reward + emit_reward( + {"final": final, "base": base, "policy_penalty": penalty}, + primary_key="final", + attributes={"agent_os.violations": violation_count}, + ) + except ImportError: + pass + + def get_stats(self) -> Dict[str, float]: + """Get reward statistics.""" + total = self._total_rewards or 1 + return { + "total_rewards": self._total_rewards, + "avg_penalty": self._total_penalties / total, + } diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py new file mode 100644 index 000000000..57a94b206 --- /dev/null +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -0,0 +1,210 @@ +""" +AgentOSRunner - Agent-Lightning Runner with Kernel Safety +========================================================== + +Wraps agent execution with Agent-OS kernel governance. +""" + +from __future__ import annotations + +import logging +from typing import Any, Generic, Optional, Sequence, TypeVar +from dataclasses import dataclass, field +from datetime import datetime + +logger = logging.getLogger(__name__) + +T_task = TypeVar("T_task") + + +@dataclass +class PolicyViolation: + """Record of a policy violation.""" + policy_name: str + description: str + severity: str + blocked: bool + timestamp: datetime = field(default_factory=datetime.utcnow) + + @property + def penalty(self) -> float: + """Calculate penalty based on severity.""" + penalties = {"critical": 100.0, "high": 50.0, "medium": 10.0, "low": 1.0} + return penalties.get(self.severity, 10.0) + + +@dataclass +class GovernedRollout: + """Rollout with governance metadata.""" + task_input: Any + task_output: Any + success: bool + violations: list[PolicyViolation] = field(default_factory=list) + + @property + def total_penalty(self) -> float: + return sum(v.penalty for v in self.violations) + + +class AgentOSRunner(Generic[T_task]): + """ + Agent-Lightning runner with Agent-OS kernel safety. + + This runner wraps agent execution in an Agent-OS kernel, + enforcing policies and collecting violation data for RL training. + + Example: + >>> from agent_os import KernelSpace + >>> from agent_os.policies import SQLPolicy + >>> + >>> kernel = KernelSpace(policy=SQLPolicy()) + >>> runner = AgentOSRunner(kernel) + >>> + >>> rollout = await runner.step(task) + >>> print(f"Violations: {len(rollout.violations)}") + """ + + def __init__( + self, + kernel: Any, + *, + fail_on_violation: bool = False, + emit_violations: bool = True, + ): + """ + Initialize the governed runner. + + Args: + kernel: Agent-OS KernelSpace with loaded policies + fail_on_violation: Raise exception on violation + emit_violations: Emit violations as spans + """ + self.kernel = kernel + self.fail_on_violation = fail_on_violation + self.emit_violations = emit_violations + + self._violations: list[PolicyViolation] = [] + self._total_rollouts = 0 + self._total_violations = 0 + + self._setup_hooks() + + def _setup_hooks(self) -> None: + """Set up kernel hooks.""" + if hasattr(self.kernel, 'on_policy_violation'): + self.kernel.on_policy_violation(self._handle_violation) + + def _handle_violation( + self, + policy_name: str, + description: str, + severity: str, + blocked: bool, + ) -> None: + """Handle a policy violation.""" + violation = PolicyViolation( + policy_name=policy_name, + description=description, + severity=severity, + blocked=blocked, + ) + self._violations.append(violation) + self._total_violations += 1 + + if self.emit_violations: + self._emit_violation_span(violation) + + if self.fail_on_violation and blocked: + raise PolicyViolationError(violation) + + def _emit_violation_span(self, violation: PolicyViolation) -> None: + """Emit violation as Agent-Lightning span.""" + try: + from agentlightning.emitter import emit_annotation + emit_annotation({ + "agent_os.violation": True, + "agent_os.policy": violation.policy_name, + "agent_os.severity": violation.severity, + "agent_os.blocked": violation.blocked, + }) + except ImportError: + pass + + def init(self, agent: Any, **kwargs: Any) -> None: + """Initialize with agent.""" + self.agent = agent + + def init_worker(self, worker_id: int, store: Any, **kwargs: Any) -> None: + """Initialize worker.""" + self.worker_id = worker_id + self.store = store + + def teardown(self) -> None: + """Release resources.""" + pass + + def teardown_worker(self, worker_id: int) -> None: + """Release worker resources.""" + pass + + async def step( + self, + input: T_task, + *, + resources: Optional[Any] = None, + mode: Optional[str] = None, + event: Optional[Any] = None, + ) -> GovernedRollout: + """ + Execute task with governance. + + Args: + input: Task input + resources: Optional resources + mode: Rollout mode + event: Stop signal + + Returns: + GovernedRollout with results and violations + """ + self._violations = [] + + try: + if hasattr(self.kernel, 'execute_async'): + result = await self.kernel.execute_async(self.agent, input) + elif hasattr(self.kernel, 'execute'): + result = self.kernel.execute(self.agent, input) + else: + result = await self.agent(input) + success = True + except PolicyViolationError: + result = None + success = False + except Exception as e: + logger.error(f"Execution failed: {e}") + result = None + success = False + + self._total_rollouts += 1 + + return GovernedRollout( + task_input=input, + task_output=result, + success=success, + violations=self._violations.copy(), + ) + + def get_stats(self) -> dict: + """Get runner statistics.""" + return { + "total_rollouts": self._total_rollouts, + "total_violations": self._total_violations, + "violation_rate": self._total_violations / max(self._total_rollouts, 1), + } + + +class PolicyViolationError(Exception): + """Raised when policy violation blocks execution.""" + def __init__(self, violation: PolicyViolation): + self.violation = violation + super().__init__(f"Policy violation: {violation.description}") From d6ce069935de97149e766b152b107a979bc68765 Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:42:26 -0800 Subject: [PATCH 02/22] Update contrib/agentlightning/contrib/agent_os/runner.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/runner.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 57a94b206..5381295c8 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -177,11 +177,9 @@ async def step( else: result = await self.agent(input) success = True - except PolicyViolationError: - result = None - success = False - except Exception as e: - logger.error(f"Execution failed: {e}") + except PolicyViolationError as e: + # Record the policy violation and mark rollout as unsuccessful. + self._violations.append(e.violation) result = None success = False From 215964686ea4ec7901c9e70927c11755a859f06d Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:42:40 -0800 Subject: [PATCH 03/22] Update contrib/agentlightning/contrib/agent_os/adapter.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/adapter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/adapter.py b/contrib/agentlightning/contrib/agent_os/adapter.py index 6761bfb19..0f25f8bed 100644 --- a/contrib/agentlightning/contrib/agent_os/adapter.py +++ b/contrib/agentlightning/contrib/agent_os/adapter.py @@ -120,5 +120,5 @@ def get_violation_summary(self) -> Dict[str, Any]: return { "total_entries": len(spans), "total_violations": len(violations), - "violation_rate": len(violations) / max(len(spans), 1), + "violation_rate": len(violations) / len(spans) if len(spans) > 0 else 0.0, } From 4c17f2683d81f98838aa8515268ecd8ebb4a0099 Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:42:53 -0800 Subject: [PATCH 04/22] Update contrib/agentlightning/contrib/agent_os/README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/README.md b/contrib/agentlightning/contrib/agent_os/README.md index 8781d4beb..1f9eb318d 100644 --- a/contrib/agentlightning/contrib/agent_os/README.md +++ b/contrib/agentlightning/contrib/agent_os/README.md @@ -14,7 +14,7 @@ for AI agents. This integration enables: ## Installation ```bash -pip install agentlightning agent-os-kernel +pip install agentlightning agent-os ``` ## Quick Start From 4843a843c6d1cfca04eccfeffe71ddac01d148a8 Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:43:20 -0800 Subject: [PATCH 05/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/reward.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/reward.py b/contrib/agentlightning/contrib/agent_os/reward.py index f9817e543..bb236f3b0 100644 --- a/contrib/agentlightning/contrib/agent_os/reward.py +++ b/contrib/agentlightning/contrib/agent_os/reward.py @@ -8,7 +8,7 @@ from __future__ import annotations import logging -from typing import Any, Callable, Dict, List, Optional +from typing import Any, Callable, Dict, Optional logger = logging.getLogger(__name__) From b04aeac92e9db5574305417adf93f934c14f520e Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:43:35 -0800 Subject: [PATCH 06/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/reward.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/reward.py b/contrib/agentlightning/contrib/agent_os/reward.py index bb236f3b0..53ba92e78 100644 --- a/contrib/agentlightning/contrib/agent_os/reward.py +++ b/contrib/agentlightning/contrib/agent_os/reward.py @@ -113,7 +113,10 @@ def _emit_reward( attributes={"agent_os.violations": violation_count}, ) except ImportError: - pass + logger.debug( + "agentlightning.emitter not available; skipping reward emission.", + exc_info=True, + ) def get_stats(self) -> Dict[str, float]: """Get reward statistics.""" From c010c6087d6a557e1c61fbf37dbb321d7f102775 Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:43:46 -0800 Subject: [PATCH 07/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 5381295c8..1fd4f7f0e 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -8,7 +8,7 @@ from __future__ import annotations import logging -from typing import Any, Generic, Optional, Sequence, TypeVar +from typing import Any, Generic, Optional, TypeVar from dataclasses import dataclass, field from datetime import datetime From a1437f18fb220e4d614eaaa5a8a46eee2cf3951f Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:45:59 -0800 Subject: [PATCH 08/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../agentlightning/contrib/agent_os/runner.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 1fd4f7f0e..5c9aee134 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -28,11 +28,19 @@ class PolicyViolation: @property def penalty(self) -> float: - """Calculate penalty based on severity.""" - penalties = {"critical": 100.0, "high": 50.0, "medium": 10.0, "low": 1.0} - return penalties.get(self.severity, 10.0) - + """Calculate penalty based on severity. + Returns: + float: Negative penalty value, where more severe violations + have larger negative magnitudes. + """ + penalties = { + "critical": -100.0, + "high": -50.0, + "medium": -10.0, + "low": -1.0, + } + return penalties.get(self.severity, -10.0) @dataclass class GovernedRollout: """Rollout with governance metadata.""" From 9b875de649562e770f36ca521c4df30519877029 Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:46:14 -0800 Subject: [PATCH 09/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../agentlightning/contrib/agent_os/runner.py | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 5c9aee134..4ddccd107 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -99,8 +99,26 @@ def __init__( def _setup_hooks(self) -> None: """Set up kernel hooks.""" - if hasattr(self.kernel, 'on_policy_violation'): - self.kernel.on_policy_violation(self._handle_violation) + on_violation = getattr(self.kernel, "on_policy_violation", None) + if on_violation is None: + logger.warning( + "Kernel %r does not support policy violation hooks via 'on_policy_violation'.", + self.kernel, + ) + return + if not callable(on_violation): + logger.warning( + "Kernel attribute 'on_policy_violation' is not callable: %r", + on_violation, + ) + return + try: + on_violation(self._handle_violation) + except TypeError as exc: + logger.warning( + "Kernel.on_policy_violation has an incompatible signature: %s", + exc, + ) def _handle_violation( self, From a1fcec24d95a791d6ab23d6cc969b90b9e6e948d Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:46:35 -0800 Subject: [PATCH 10/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/runner.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 4ddccd107..5a526f8bb 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -153,8 +153,11 @@ def _emit_violation_span(self, violation: PolicyViolation) -> None: "agent_os.severity": violation.severity, "agent_os.blocked": violation.blocked, }) - except ImportError: - pass + except ImportError as exc: + logger.debug( + "agentlightning.emitter not available; skipping violation annotation: %s", + exc, + ) def init(self, agent: Any, **kwargs: Any) -> None: """Initialize with agent.""" From faf82f87b8958895a65f8681db2902319dc3a099 Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:46:50 -0800 Subject: [PATCH 11/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../agentlightning/contrib/agent_os/runner.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 5a526f8bb..3315f9dd0 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -159,6 +159,24 @@ def _emit_violation_span(self, violation: PolicyViolation) -> None: exc, ) + @property + def agent(self) -> Any: + """ + Access the underlying agent. + + Raises: + RuntimeError: If the agent has not been initialized via `init`. + """ + if not hasattr(self, "_agent"): + raise RuntimeError( + "AgentOSRunner.agent accessed before `init` has been called." + ) + return self._agent + + @agent.setter + def agent(self, value: Any) -> None: + """Set the underlying agent instance.""" + self._agent = value def init(self, agent: Any, **kwargs: Any) -> None: """Initialize with agent.""" self.agent = agent From c23cdac83d321c0191f2e4d9e68b0d50ad4b67fd Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:47:05 -0800 Subject: [PATCH 12/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/runner.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 3315f9dd0..b43f8d23b 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -218,11 +218,19 @@ async def step( try: if hasattr(self.kernel, 'execute_async'): + logger.debug("AgentOSRunner: executing task via kernel.execute_async") result = await self.kernel.execute_async(self.agent, input) elif hasattr(self.kernel, 'execute'): + logger.debug("AgentOSRunner: executing task via kernel.execute") result = self.kernel.execute(self.agent, input) else: - result = await self.agent(input) + logger.error( + "AgentOSRunner: kernel does not support 'execute_async' or 'execute'; " + "governed execution is not possible." + ) + raise RuntimeError( + "Kernel does not support governed execution (missing 'execute_async' and 'execute')." + ) success = True except PolicyViolationError as e: # Record the policy violation and mark rollout as unsuccessful. From 8d241fd82a0b0f298d6945fa4fa2c6eaeb2513af Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:49:55 -0800 Subject: [PATCH 13/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/runner.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index b43f8d23b..04384c6b1 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -252,7 +252,11 @@ def get_stats(self) -> dict: return { "total_rollouts": self._total_rollouts, "total_violations": self._total_violations, - "violation_rate": self._total_violations / max(self._total_rollouts, 1), + "violation_rate": ( + self._total_violations / self._total_rollouts + if self._total_rollouts > 0 + else 0.0 + ), } From 31f52d3570c8bd6899928be634b723d4185cb530 Mon Sep 17 00:00:00 2001 From: Imran Siddique <45405841+imran-siddique@users.noreply.github.com> Date: Thu, 5 Feb 2026 11:50:22 -0800 Subject: [PATCH 14/22] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- contrib/agentlightning/contrib/agent_os/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/README.md b/contrib/agentlightning/contrib/agent_os/README.md index 1f9eb318d..6b4d1c1a8 100644 --- a/contrib/agentlightning/contrib/agent_os/README.md +++ b/contrib/agentlightning/contrib/agent_os/README.md @@ -95,7 +95,7 @@ adapter.import_to_store(lightning_store) ## Documentation - [Agent-OS Documentation](https://imran-siddique.github.io/agent-os-docs/) -- [Integration Guide](./docs/integration.md) +- Integration guide: see project README or examples in this directory. ## License From 7b46f6cdd93c3d4bf45ac7957841ff3215874121 Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 12:14:21 -0800 Subject: [PATCH 15/22] fix: apply ruff formatting (trailing whitespace, double quotes) --- .../contrib/agent_os/adapter.py | 48 +++++++++--------- .../agentlightning/contrib/agent_os/reward.py | 26 +++++----- .../agentlightning/contrib/agent_os/runner.py | 50 ++++++++++--------- 3 files changed, 64 insertions(+), 60 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/adapter.py b/contrib/agentlightning/contrib/agent_os/adapter.py index 0f25f8bed..5e751b6cc 100644 --- a/contrib/agentlightning/contrib/agent_os/adapter.py +++ b/contrib/agentlightning/contrib/agent_os/adapter.py @@ -27,7 +27,7 @@ class FlightRecorderAdapter: >>> # Import to Lightning store >>> adapter.import_to_store(lightning_store) """ - + def __init__( self, flight_recorder: Any, @@ -44,47 +44,47 @@ def __init__( self.recorder = flight_recorder self.trace_id_prefix = trace_id_prefix self._imported_count = 0 - + def _convert_entry(self, entry: Any, index: int) -> Dict[str, Any]: """Convert Flight Recorder entry to span format.""" - entry_type = getattr(entry, 'type', 'unknown') - timestamp = getattr(entry, 'timestamp', datetime.utcnow()) - agent_id = getattr(entry, 'agent_id', 'unknown') - + entry_type = getattr(entry, "type", "unknown") + timestamp = getattr(entry, "timestamp", datetime.utcnow()) + agent_id = getattr(entry, "agent_id", "unknown") + span = { "span_id": f"{self.trace_id_prefix}-{index}", "trace_id": f"{self.trace_id_prefix}-{agent_id}", "name": f"agent_os.{entry_type}", - "start_time": timestamp.isoformat() if hasattr(timestamp, 'isoformat') else str(timestamp), + "start_time": timestamp.isoformat() if hasattr(timestamp, "isoformat") else str(timestamp), "attributes": { "agent_os.entry_type": entry_type, "agent_os.agent_id": agent_id, }, } - + # Add type-specific attributes - if entry_type == 'policy_check': + if entry_type == "policy_check": span["attributes"].update({ - "agent_os.policy_name": getattr(entry, 'policy_name', 'unknown'), - "agent_os.policy_violated": getattr(entry, 'violated', False), + "agent_os.policy_name": getattr(entry, "policy_name", "unknown"), + "agent_os.policy_violated": getattr(entry, "violated", False), }) - elif entry_type == 'signal': + elif entry_type == "signal": span["attributes"].update({ - "agent_os.signal_type": getattr(entry, 'signal', 'unknown'), + "agent_os.signal_type": getattr(entry, "signal", "unknown"), }) - + return span - + def get_spans(self) -> List[Dict[str, Any]]: """Get all entries as spans.""" entries = [] - if hasattr(self.recorder, 'get_entries'): + if hasattr(self.recorder, "get_entries"): entries = self.recorder.get_entries() - elif hasattr(self.recorder, 'entries'): + elif hasattr(self.recorder, "entries"): entries = self.recorder.entries - + return [self._convert_entry(e, i) for i, e in enumerate(entries)] - + def import_to_store(self, store: Any) -> int: """ Import spans to LightningStore. @@ -96,20 +96,20 @@ def import_to_store(self, store: Any) -> int: Number of spans imported """ spans = self.get_spans() - + for span in spans: try: - if hasattr(store, 'emit_span'): + if hasattr(store, "emit_span"): store.emit_span(span) - elif hasattr(store, 'add_span'): + elif hasattr(store, "add_span"): store.add_span(span) except Exception as e: logger.error(f"Failed to import span: {e}") - + self._imported_count += len(spans) logger.info(f"Imported {len(spans)} spans to LightningStore") return len(spans) - + def get_violation_summary(self) -> Dict[str, Any]: """Get summary of policy violations.""" spans = self.get_spans() diff --git a/contrib/agentlightning/contrib/agent_os/reward.py b/contrib/agentlightning/contrib/agent_os/reward.py index 53ba92e78..38323c6fb 100644 --- a/contrib/agentlightning/contrib/agent_os/reward.py +++ b/contrib/agentlightning/contrib/agent_os/reward.py @@ -25,7 +25,7 @@ class PolicyReward: >>> >>> reward = reward_fn(rollout) # Base reward - violation penalties """ - + def __init__( self, kernel: Any, @@ -58,14 +58,14 @@ def __init__( "low": low_penalty, } self.clean_bonus = clean_bonus - + self._total_rewards = 0 self._total_penalties = 0.0 - + def _default_reward(self, rollout: Any) -> float: """Default: 1.0 for success, 0.0 for failure.""" - return 1.0 if getattr(rollout, 'success', False) else 0.0 - + return 1.0 if getattr(rollout, "success", False) else 0.0 + def __call__(self, rollout: Any, *, emit: bool = True) -> float: """ Calculate reward with policy penalties. @@ -78,25 +78,25 @@ def __call__(self, rollout: Any, *, emit: bool = True) -> float: Final reward """ base = self.base_reward_fn(rollout) - - violations = getattr(rollout, 'violations', []) + + violations = getattr(rollout, "violations", []) penalty = sum( self.penalties.get(v.severity, -10.0) for v in violations ) - + reward = base + penalty if not violations: reward += self.clean_bonus - + self._total_rewards += 1 self._total_penalties += penalty - + if emit: self._emit_reward(reward, base, penalty, len(violations)) - + return reward - + def _emit_reward( self, final: float, @@ -117,7 +117,7 @@ def _emit_reward( "agentlightning.emitter not available; skipping reward emission.", exc_info=True, ) - + def get_stats(self) -> Dict[str, float]: """Get reward statistics.""" total = self._total_rewards or 1 diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 04384c6b1..a6a4dfa04 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -25,7 +25,7 @@ class PolicyViolation: severity: str blocked: bool timestamp: datetime = field(default_factory=datetime.utcnow) - + @property def penalty(self) -> float: """Calculate penalty based on severity. @@ -41,6 +41,8 @@ def penalty(self) -> float: "low": -1.0, } return penalties.get(self.severity, -10.0) + + @dataclass class GovernedRollout: """Rollout with governance metadata.""" @@ -48,7 +50,7 @@ class GovernedRollout: task_output: Any success: bool violations: list[PolicyViolation] = field(default_factory=list) - + @property def total_penalty(self) -> float: return sum(v.penalty for v in self.violations) @@ -71,7 +73,7 @@ class AgentOSRunner(Generic[T_task]): >>> rollout = await runner.step(task) >>> print(f"Violations: {len(rollout.violations)}") """ - + def __init__( self, kernel: Any, @@ -90,13 +92,13 @@ def __init__( self.kernel = kernel self.fail_on_violation = fail_on_violation self.emit_violations = emit_violations - + self._violations: list[PolicyViolation] = [] self._total_rollouts = 0 self._total_violations = 0 - + self._setup_hooks() - + def _setup_hooks(self) -> None: """Set up kernel hooks.""" on_violation = getattr(self.kernel, "on_policy_violation", None) @@ -119,7 +121,7 @@ def _setup_hooks(self) -> None: "Kernel.on_policy_violation has an incompatible signature: %s", exc, ) - + def _handle_violation( self, policy_name: str, @@ -136,13 +138,13 @@ def _handle_violation( ) self._violations.append(violation) self._total_violations += 1 - + if self.emit_violations: self._emit_violation_span(violation) - + if self.fail_on_violation and blocked: raise PolicyViolationError(violation) - + def _emit_violation_span(self, violation: PolicyViolation) -> None: """Emit violation as Agent-Lightning span.""" try: @@ -158,7 +160,7 @@ def _emit_violation_span(self, violation: PolicyViolation) -> None: "agentlightning.emitter not available; skipping violation annotation: %s", exc, ) - + @property def agent(self) -> Any: """ @@ -177,23 +179,24 @@ def agent(self) -> Any: def agent(self, value: Any) -> None: """Set the underlying agent instance.""" self._agent = value + def init(self, agent: Any, **kwargs: Any) -> None: """Initialize with agent.""" self.agent = agent - + def init_worker(self, worker_id: int, store: Any, **kwargs: Any) -> None: """Initialize worker.""" self.worker_id = worker_id self.store = store - + def teardown(self) -> None: """Release resources.""" pass - + def teardown_worker(self, worker_id: int) -> None: """Release worker resources.""" pass - + async def step( self, input: T_task, @@ -204,23 +207,23 @@ async def step( ) -> GovernedRollout: """ Execute task with governance. - + Args: input: Task input resources: Optional resources mode: Rollout mode event: Stop signal - + Returns: GovernedRollout with results and violations """ self._violations = [] - + try: - if hasattr(self.kernel, 'execute_async'): + if hasattr(self.kernel, "execute_async"): logger.debug("AgentOSRunner: executing task via kernel.execute_async") result = await self.kernel.execute_async(self.agent, input) - elif hasattr(self.kernel, 'execute'): + elif hasattr(self.kernel, "execute"): logger.debug("AgentOSRunner: executing task via kernel.execute") result = self.kernel.execute(self.agent, input) else: @@ -237,16 +240,16 @@ async def step( self._violations.append(e.violation) result = None success = False - + self._total_rollouts += 1 - + return GovernedRollout( task_input=input, task_output=result, success=success, violations=self._violations.copy(), ) - + def get_stats(self) -> dict: """Get runner statistics.""" return { @@ -262,6 +265,7 @@ def get_stats(self) -> dict: class PolicyViolationError(Exception): """Raised when policy violation blocks execution.""" + def __init__(self, violation: PolicyViolation): self.violation = violation super().__init__(f"Policy violation: {violation.description}") From 6ca64c459ffe9ff653640c54671c4810563358d4 Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 12:14:52 -0800 Subject: [PATCH 16/22] fix: remove trailing whitespace in __init__.py --- contrib/agentlightning/contrib/agent_os/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/__init__.py b/contrib/agentlightning/contrib/agent_os/__init__.py index a30663620..aa2f2a318 100644 --- a/contrib/agentlightning/contrib/agent_os/__init__.py +++ b/contrib/agentlightning/contrib/agent_os/__init__.py @@ -12,7 +12,7 @@ Example: >>> from agentlightning.contrib.agent_os import AgentOSRunner, PolicyReward >>> from agent_os import KernelSpace - >>> + >>> >>> kernel = KernelSpace(policy="safety-critical") >>> runner = AgentOSRunner(kernel) >>> reward_fn = PolicyReward(kernel) From 7da4e0db85c568ebeb645f98d1107b3e60d4284d Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 12:28:25 -0800 Subject: [PATCH 17/22] fix: apply ruff format to match project style --- .../contrib/agent_os/adapter.py | 37 +++++++++++-------- .../agentlightning/contrib/agent_os/reward.py | 18 ++++----- .../agentlightning/contrib/agent_os/runner.py | 27 ++++++++------ 3 files changed, 45 insertions(+), 37 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/adapter.py b/contrib/agentlightning/contrib/agent_os/adapter.py index 5e751b6cc..06b2145bd 100644 --- a/contrib/agentlightning/contrib/agent_os/adapter.py +++ b/contrib/agentlightning/contrib/agent_os/adapter.py @@ -17,13 +17,13 @@ class FlightRecorderAdapter: """ Import Agent-OS Flight Recorder logs to LightningStore. - + Example: >>> from agent_os import FlightRecorder - >>> + >>> >>> recorder = FlightRecorder() >>> adapter = FlightRecorderAdapter(recorder) - >>> + >>> >>> # Import to Lightning store >>> adapter.import_to_store(lightning_store) """ @@ -36,7 +36,7 @@ def __init__( ): """ Initialize adapter. - + Args: flight_recorder: Agent-OS FlightRecorder trace_id_prefix: Prefix for trace IDs @@ -55,7 +55,9 @@ def _convert_entry(self, entry: Any, index: int) -> Dict[str, Any]: "span_id": f"{self.trace_id_prefix}-{index}", "trace_id": f"{self.trace_id_prefix}-{agent_id}", "name": f"agent_os.{entry_type}", - "start_time": timestamp.isoformat() if hasattr(timestamp, "isoformat") else str(timestamp), + "start_time": timestamp.isoformat() + if hasattr(timestamp, "isoformat") + else str(timestamp), "attributes": { "agent_os.entry_type": entry_type, "agent_os.agent_id": agent_id, @@ -64,14 +66,18 @@ def _convert_entry(self, entry: Any, index: int) -> Dict[str, Any]: # Add type-specific attributes if entry_type == "policy_check": - span["attributes"].update({ - "agent_os.policy_name": getattr(entry, "policy_name", "unknown"), - "agent_os.policy_violated": getattr(entry, "violated", False), - }) + span["attributes"].update( + { + "agent_os.policy_name": getattr(entry, "policy_name", "unknown"), + "agent_os.policy_violated": getattr(entry, "violated", False), + } + ) elif entry_type == "signal": - span["attributes"].update({ - "agent_os.signal_type": getattr(entry, "signal", "unknown"), - }) + span["attributes"].update( + { + "agent_os.signal_type": getattr(entry, "signal", "unknown"), + } + ) return span @@ -88,10 +94,10 @@ def get_spans(self) -> List[Dict[str, Any]]: def import_to_store(self, store: Any) -> int: """ Import spans to LightningStore. - + Args: store: LightningStore instance - + Returns: Number of spans imported """ @@ -114,8 +120,7 @@ def get_violation_summary(self) -> Dict[str, Any]: """Get summary of policy violations.""" spans = self.get_spans() violations = [ - s for s in spans - if s["attributes"].get("agent_os.policy_violated", False) + s for s in spans if s["attributes"].get("agent_os.policy_violated", False) ] return { "total_entries": len(spans), diff --git a/contrib/agentlightning/contrib/agent_os/reward.py b/contrib/agentlightning/contrib/agent_os/reward.py index 38323c6fb..1685f76cb 100644 --- a/contrib/agentlightning/contrib/agent_os/reward.py +++ b/contrib/agentlightning/contrib/agent_os/reward.py @@ -16,13 +16,13 @@ class PolicyReward: """ Reward function that penalizes policy violations. - + Example: >>> from agent_os import KernelSpace - >>> + >>> >>> kernel = KernelSpace(policy="strict") >>> reward_fn = PolicyReward(kernel, base_reward_fn=accuracy) - >>> + >>> >>> reward = reward_fn(rollout) # Base reward - violation penalties """ @@ -39,7 +39,7 @@ def __init__( ): """ Initialize policy-aware reward. - + Args: kernel: Agent-OS KernelSpace base_reward_fn: Base reward function @@ -69,21 +69,18 @@ def _default_reward(self, rollout: Any) -> float: def __call__(self, rollout: Any, *, emit: bool = True) -> float: """ Calculate reward with policy penalties. - + Args: rollout: Rollout with violations attribute emit: Emit reward span - + Returns: Final reward """ base = self.base_reward_fn(rollout) violations = getattr(rollout, "violations", []) - penalty = sum( - self.penalties.get(v.severity, -10.0) - for v in violations - ) + penalty = sum(self.penalties.get(v.severity, -10.0) for v in violations) reward = base + penalty if not violations: @@ -107,6 +104,7 @@ def _emit_reward( """Emit multi-dimensional reward.""" try: from agentlightning.emitter import emit_reward + emit_reward( {"final": final, "base": base, "policy_penalty": penalty}, primary_key="final", diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index a6a4dfa04..788b749ee 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -20,6 +20,7 @@ @dataclass class PolicyViolation: """Record of a policy violation.""" + policy_name: str description: str severity: str @@ -46,6 +47,7 @@ def penalty(self) -> float: @dataclass class GovernedRollout: """Rollout with governance metadata.""" + task_input: Any task_output: Any success: bool @@ -59,17 +61,17 @@ def total_penalty(self) -> float: class AgentOSRunner(Generic[T_task]): """ Agent-Lightning runner with Agent-OS kernel safety. - + This runner wraps agent execution in an Agent-OS kernel, enforcing policies and collecting violation data for RL training. - + Example: >>> from agent_os import KernelSpace >>> from agent_os.policies import SQLPolicy - >>> + >>> >>> kernel = KernelSpace(policy=SQLPolicy()) >>> runner = AgentOSRunner(kernel) - >>> + >>> >>> rollout = await runner.step(task) >>> print(f"Violations: {len(rollout.violations)}") """ @@ -83,7 +85,7 @@ def __init__( ): """ Initialize the governed runner. - + Args: kernel: Agent-OS KernelSpace with loaded policies fail_on_violation: Raise exception on violation @@ -149,12 +151,15 @@ def _emit_violation_span(self, violation: PolicyViolation) -> None: """Emit violation as Agent-Lightning span.""" try: from agentlightning.emitter import emit_annotation - emit_annotation({ - "agent_os.violation": True, - "agent_os.policy": violation.policy_name, - "agent_os.severity": violation.severity, - "agent_os.blocked": violation.blocked, - }) + + emit_annotation( + { + "agent_os.violation": True, + "agent_os.policy": violation.policy_name, + "agent_os.severity": violation.severity, + "agent_os.blocked": violation.blocked, + } + ) except ImportError as exc: logger.debug( "agentlightning.emitter not available; skipping violation annotation: %s", From ba2199489f7f781d888c2e5e8a0be48e640760f3 Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 12:51:12 -0800 Subject: [PATCH 18/22] fix: apply black/isort formatting for pre-commit compliance --- contrib/agentlightning/contrib/agent_os/__init__.py | 4 ++-- contrib/agentlightning/contrib/agent_os/adapter.py | 10 +++------- contrib/agentlightning/contrib/agent_os/runner.py | 12 +++--------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/__init__.py b/contrib/agentlightning/contrib/agent_os/__init__.py index aa2f2a318..37860843d 100644 --- a/contrib/agentlightning/contrib/agent_os/__init__.py +++ b/contrib/agentlightning/contrib/agent_os/__init__.py @@ -18,9 +18,9 @@ >>> reward_fn = PolicyReward(kernel) """ -from .runner import AgentOSRunner -from .reward import PolicyReward from .adapter import FlightRecorderAdapter +from .reward import PolicyReward +from .runner import AgentOSRunner __all__ = [ "AgentOSRunner", diff --git a/contrib/agentlightning/contrib/agent_os/adapter.py b/contrib/agentlightning/contrib/agent_os/adapter.py index 06b2145bd..e3bf0a7be 100644 --- a/contrib/agentlightning/contrib/agent_os/adapter.py +++ b/contrib/agentlightning/contrib/agent_os/adapter.py @@ -8,8 +8,8 @@ from __future__ import annotations import logging -from typing import Any, Dict, List from datetime import datetime +from typing import Any, Dict, List logger = logging.getLogger(__name__) @@ -55,9 +55,7 @@ def _convert_entry(self, entry: Any, index: int) -> Dict[str, Any]: "span_id": f"{self.trace_id_prefix}-{index}", "trace_id": f"{self.trace_id_prefix}-{agent_id}", "name": f"agent_os.{entry_type}", - "start_time": timestamp.isoformat() - if hasattr(timestamp, "isoformat") - else str(timestamp), + "start_time": timestamp.isoformat() if hasattr(timestamp, "isoformat") else str(timestamp), "attributes": { "agent_os.entry_type": entry_type, "agent_os.agent_id": agent_id, @@ -119,9 +117,7 @@ def import_to_store(self, store: Any) -> int: def get_violation_summary(self) -> Dict[str, Any]: """Get summary of policy violations.""" spans = self.get_spans() - violations = [ - s for s in spans if s["attributes"].get("agent_os.policy_violated", False) - ] + violations = [s for s in spans if s["attributes"].get("agent_os.policy_violated", False)] return { "total_entries": len(spans), "total_violations": len(violations), diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 788b749ee..695a07a4f 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -8,9 +8,9 @@ from __future__ import annotations import logging -from typing import Any, Generic, Optional, TypeVar from dataclasses import dataclass, field from datetime import datetime +from typing import Any, Generic, Optional, TypeVar logger = logging.getLogger(__name__) @@ -175,9 +175,7 @@ def agent(self) -> Any: RuntimeError: If the agent has not been initialized via `init`. """ if not hasattr(self, "_agent"): - raise RuntimeError( - "AgentOSRunner.agent accessed before `init` has been called." - ) + raise RuntimeError("AgentOSRunner.agent accessed before `init` has been called.") return self._agent @agent.setter @@ -260,11 +258,7 @@ def get_stats(self) -> dict: return { "total_rollouts": self._total_rollouts, "total_violations": self._total_violations, - "violation_rate": ( - self._total_violations / self._total_rollouts - if self._total_rollouts > 0 - else 0.0 - ), + "violation_rate": (self._total_violations / self._total_rollouts if self._total_rollouts > 0 else 0.0), } From 5d9a8182c65230aeb864b4a38b7dcf4c1be4a3e4 Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 12:55:15 -0800 Subject: [PATCH 19/22] fix: add Microsoft copyright headers --- contrib/agentlightning/contrib/agent_os/__init__.py | 1 + contrib/agentlightning/contrib/agent_os/adapter.py | 1 + contrib/agentlightning/contrib/agent_os/reward.py | 1 + contrib/agentlightning/contrib/agent_os/runner.py | 1 + 4 files changed, 4 insertions(+) diff --git a/contrib/agentlightning/contrib/agent_os/__init__.py b/contrib/agentlightning/contrib/agent_os/__init__.py index 37860843d..d8fbaff99 100644 --- a/contrib/agentlightning/contrib/agent_os/__init__.py +++ b/contrib/agentlightning/contrib/agent_os/__init__.py @@ -1,3 +1,4 @@ +# Copyright (c) Microsoft. All rights reserved. """ Agent-OS Integration for Agent-Lightning ========================================= diff --git a/contrib/agentlightning/contrib/agent_os/adapter.py b/contrib/agentlightning/contrib/agent_os/adapter.py index e3bf0a7be..90a322069 100644 --- a/contrib/agentlightning/contrib/agent_os/adapter.py +++ b/contrib/agentlightning/contrib/agent_os/adapter.py @@ -1,3 +1,4 @@ +# Copyright (c) Microsoft. All rights reserved. """ FlightRecorderAdapter - Import Audit Logs to LightningStore ============================================================= diff --git a/contrib/agentlightning/contrib/agent_os/reward.py b/contrib/agentlightning/contrib/agent_os/reward.py index 1685f76cb..b566b2a60 100644 --- a/contrib/agentlightning/contrib/agent_os/reward.py +++ b/contrib/agentlightning/contrib/agent_os/reward.py @@ -1,3 +1,4 @@ +# Copyright (c) Microsoft. All rights reserved. """ PolicyReward - Convert Policy Violations to RL Penalties ========================================================= diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 695a07a4f..6659fa784 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -1,3 +1,4 @@ +# Copyright (c) Microsoft. All rights reserved. """ AgentOSRunner - Agent-Lightning Runner with Kernel Safety ========================================================== From 945cfcb0e0a1b5688eb0a70d83e1f618ffad638d Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 13:01:25 -0800 Subject: [PATCH 20/22] fix: add blank line after copyright headers --- contrib/agentlightning/contrib/agent_os/__init__.py | 1 + contrib/agentlightning/contrib/agent_os/adapter.py | 1 + contrib/agentlightning/contrib/agent_os/reward.py | 1 + contrib/agentlightning/contrib/agent_os/runner.py | 1 + 4 files changed, 4 insertions(+) diff --git a/contrib/agentlightning/contrib/agent_os/__init__.py b/contrib/agentlightning/contrib/agent_os/__init__.py index d8fbaff99..8995c5339 100644 --- a/contrib/agentlightning/contrib/agent_os/__init__.py +++ b/contrib/agentlightning/contrib/agent_os/__init__.py @@ -1,4 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. + """ Agent-OS Integration for Agent-Lightning ========================================= diff --git a/contrib/agentlightning/contrib/agent_os/adapter.py b/contrib/agentlightning/contrib/agent_os/adapter.py index 90a322069..5c17c090a 100644 --- a/contrib/agentlightning/contrib/agent_os/adapter.py +++ b/contrib/agentlightning/contrib/agent_os/adapter.py @@ -1,4 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. + """ FlightRecorderAdapter - Import Audit Logs to LightningStore ============================================================= diff --git a/contrib/agentlightning/contrib/agent_os/reward.py b/contrib/agentlightning/contrib/agent_os/reward.py index b566b2a60..e3fbb7fdc 100644 --- a/contrib/agentlightning/contrib/agent_os/reward.py +++ b/contrib/agentlightning/contrib/agent_os/reward.py @@ -1,4 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. + """ PolicyReward - Convert Policy Violations to RL Penalties ========================================================= diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 6659fa784..f54e18751 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -1,4 +1,5 @@ # Copyright (c) Microsoft. All rights reserved. + """ AgentOSRunner - Agent-Lightning Runner with Kernel Safety ========================================================== From c0a1d7a7b1fd314593d269d00503c4e31e1259e6 Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 14:35:08 -0800 Subject: [PATCH 21/22] fix: Address review comments - Add worker_id/store type hints in __init__ - Use timezone-aware datetime.now(timezone.utc) - Clarify benchmark claims in README (0% undetected violations) --- contrib/agentlightning/contrib/agent_os/README.md | 6 ++++-- contrib/agentlightning/contrib/agent_os/runner.py | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/contrib/agentlightning/contrib/agent_os/README.md b/contrib/agentlightning/contrib/agent_os/README.md index 6b4d1c1a8..a95c54945 100644 --- a/contrib/agentlightning/contrib/agent_os/README.md +++ b/contrib/agentlightning/contrib/agent_os/README.md @@ -7,7 +7,7 @@ Kernel-level safety during AI agent training. [Agent-OS](https://github.com/imran-siddique/agent-os) provides deterministic governance for AI agents. This integration enables: -- **0% policy violations during training** - Unsafe actions are blocked or penalized +- **0% unpenalized policy violations** - All unsafe actions are detected and penalized - **Policy violations → RL penalties** - Agents learn to avoid unsafe behavior - **Complete audit trail** - From training to production @@ -89,9 +89,11 @@ adapter.import_to_store(lightning_store) | Metric | Without Agent-OS | With Agent-OS | |--------|------------------|---------------| -| Policy Violations | 12.3% | **0.0%** | +| Undetected Policy Violations | 12.3% | **0.0%** | | Task Accuracy | 76.4% | **79.2%** | +*Note: "0% undetected violations" means all policy violations are caught and penalized, not that agents never attempt unsafe actions. Over training, agents learn to minimize violation attempts.* + ## Documentation - [Agent-OS Documentation](https://imran-siddique.github.io/agent-os-docs/) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index f54e18751..48ad2b604 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -11,7 +11,7 @@ import logging from dataclasses import dataclass, field -from datetime import datetime +from datetime import datetime, timezone from typing import Any, Generic, Optional, TypeVar logger = logging.getLogger(__name__) @@ -27,7 +27,7 @@ class PolicyViolation: description: str severity: str blocked: bool - timestamp: datetime = field(default_factory=datetime.utcnow) + timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc)) @property def penalty(self) -> float: @@ -101,6 +101,10 @@ def __init__( self._total_rollouts = 0 self._total_violations = 0 + # Worker attributes (set by init_worker) + self.worker_id: Optional[int] = None + self.store: Optional[Any] = None + self._setup_hooks() def _setup_hooks(self) -> None: From 26213601f716d1c329b2b8b8ef57c02c63897d9a Mon Sep 17 00:00:00 2001 From: Imran Siddique Date: Thu, 5 Feb 2026 15:56:40 -0800 Subject: [PATCH 22/22] fix: Add GovernedRollout docstring explaining Rollout compatibility Clarifies that GovernedRollout provides the core Rollout interface (task_input, task_output, success) plus governance-specific metadata. --- contrib/agentlightning/contrib/agent_os/runner.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/agentlightning/contrib/agent_os/runner.py b/contrib/agentlightning/contrib/agent_os/runner.py index 48ad2b604..fc1848973 100644 --- a/contrib/agentlightning/contrib/agent_os/runner.py +++ b/contrib/agentlightning/contrib/agent_os/runner.py @@ -48,7 +48,13 @@ def penalty(self) -> float: @dataclass class GovernedRollout: - """Rollout with governance metadata.""" + """Rollout with governance metadata. + + This dataclass wraps execution results with governance information. + It is compatible with Agent-Lightning's Rollout interface - the + `task_input`, `task_output`, and `success` fields provide the core + rollout data, while `violations` adds governance-specific metadata. + """ task_input: Any task_output: Any