agent_os_kernel 3.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. agent_control_plane/__init__.py +662 -0
  2. agent_control_plane/a2a_adapter.py +543 -0
  3. agent_control_plane/adapter.py +417 -0
  4. agent_control_plane/agent_hibernation.py +394 -0
  5. agent_control_plane/agent_kernel.py +470 -0
  6. agent_control_plane/compliance.py +720 -0
  7. agent_control_plane/constraint_graphs.py +478 -0
  8. agent_control_plane/control_plane.py +854 -0
  9. agent_control_plane/example_executors.py +195 -0
  10. agent_control_plane/execution_engine.py +231 -0
  11. agent_control_plane/flight_recorder.py +846 -0
  12. agent_control_plane/governance_layer.py +435 -0
  13. agent_control_plane/hf_utils.py +563 -0
  14. agent_control_plane/interfaces/__init__.py +55 -0
  15. agent_control_plane/interfaces/kernel_interface.py +361 -0
  16. agent_control_plane/interfaces/plugin_interface.py +497 -0
  17. agent_control_plane/interfaces/protocol_interfaces.py +387 -0
  18. agent_control_plane/kernel_space.py +1009 -0
  19. agent_control_plane/langchain_adapter.py +424 -0
  20. agent_control_plane/lifecycle.py +3113 -0
  21. agent_control_plane/mcp_adapter.py +653 -0
  22. agent_control_plane/ml_safety.py +563 -0
  23. agent_control_plane/multimodal.py +727 -0
  24. agent_control_plane/mute_agent.py +422 -0
  25. agent_control_plane/observability.py +787 -0
  26. agent_control_plane/orchestrator.py +482 -0
  27. agent_control_plane/plugin_registry.py +750 -0
  28. agent_control_plane/policy_engine.py +954 -0
  29. agent_control_plane/process_isolation.py +777 -0
  30. agent_control_plane/shadow_mode.py +310 -0
  31. agent_control_plane/signals.py +493 -0
  32. agent_control_plane/supervisor_agents.py +430 -0
  33. agent_control_plane/time_travel_debugger.py +557 -0
  34. agent_control_plane/tool_registry.py +452 -0
  35. agent_control_plane/vfs.py +697 -0
  36. agent_kernel/__init__.py +69 -0
  37. agent_kernel/analyzer.py +435 -0
  38. agent_kernel/auditor.py +36 -0
  39. agent_kernel/completeness_auditor.py +237 -0
  40. agent_kernel/detector.py +203 -0
  41. agent_kernel/kernel.py +744 -0
  42. agent_kernel/memory_manager.py +85 -0
  43. agent_kernel/models.py +374 -0
  44. agent_kernel/nudge_mechanism.py +263 -0
  45. agent_kernel/outcome_analyzer.py +338 -0
  46. agent_kernel/patcher.py +582 -0
  47. agent_kernel/semantic_analyzer.py +316 -0
  48. agent_kernel/semantic_purge.py +349 -0
  49. agent_kernel/simulator.py +449 -0
  50. agent_kernel/teacher.py +85 -0
  51. agent_kernel/triage.py +152 -0
  52. agent_os/__init__.py +409 -0
  53. agent_os/_adversarial_impl.py +200 -0
  54. agent_os/_circuit_breaker_impl.py +232 -0
  55. agent_os/_mcp_metrics.py +193 -0
  56. agent_os/adversarial.py +20 -0
  57. agent_os/agents_compat.py +490 -0
  58. agent_os/audit_logger.py +135 -0
  59. agent_os/base_agent.py +651 -0
  60. agent_os/circuit_breaker.py +34 -0
  61. agent_os/cli/__init__.py +659 -0
  62. agent_os/cli/cmd_audit.py +128 -0
  63. agent_os/cli/cmd_init.py +152 -0
  64. agent_os/cli/cmd_policy.py +41 -0
  65. agent_os/cli/cmd_policy_gen.py +180 -0
  66. agent_os/cli/cmd_validate.py +258 -0
  67. agent_os/cli/mcp_scan.py +265 -0
  68. agent_os/cli/output.py +192 -0
  69. agent_os/cli/policy_checker.py +330 -0
  70. agent_os/compat.py +74 -0
  71. agent_os/constraint_graph.py +234 -0
  72. agent_os/content_governance.py +140 -0
  73. agent_os/context_budget.py +305 -0
  74. agent_os/credential_redactor.py +224 -0
  75. agent_os/diff_policy.py +89 -0
  76. agent_os/egress_policy.py +159 -0
  77. agent_os/escalation.py +276 -0
  78. agent_os/event_bus.py +124 -0
  79. agent_os/exceptions.py +180 -0
  80. agent_os/execution_context_policy.py +141 -0
  81. agent_os/github_enterprise.py +96 -0
  82. agent_os/health.py +20 -0
  83. agent_os/integrations/__init__.py +279 -0
  84. agent_os/integrations/a2a_adapter.py +279 -0
  85. agent_os/integrations/agent_lightning/__init__.py +30 -0
  86. agent_os/integrations/anthropic_adapter.py +420 -0
  87. agent_os/integrations/autogen_adapter.py +620 -0
  88. agent_os/integrations/base.py +1137 -0
  89. agent_os/integrations/compat.py +229 -0
  90. agent_os/integrations/config.py +98 -0
  91. agent_os/integrations/conversation_guardian.py +957 -0
  92. agent_os/integrations/crewai_adapter.py +467 -0
  93. agent_os/integrations/drift_detector.py +425 -0
  94. agent_os/integrations/dry_run.py +124 -0
  95. agent_os/integrations/escalation.py +582 -0
  96. agent_os/integrations/gemini_adapter.py +364 -0
  97. agent_os/integrations/google_adk_adapter.py +633 -0
  98. agent_os/integrations/guardrails_adapter.py +394 -0
  99. agent_os/integrations/health.py +197 -0
  100. agent_os/integrations/langchain_adapter.py +654 -0
  101. agent_os/integrations/llamafirewall.py +343 -0
  102. agent_os/integrations/llamaindex_adapter.py +188 -0
  103. agent_os/integrations/logging.py +191 -0
  104. agent_os/integrations/maf_adapter.py +631 -0
  105. agent_os/integrations/mistral_adapter.py +365 -0
  106. agent_os/integrations/openai_adapter.py +816 -0
  107. agent_os/integrations/openai_agents_sdk.py +406 -0
  108. agent_os/integrations/policy_compose.py +171 -0
  109. agent_os/integrations/profiling.py +144 -0
  110. agent_os/integrations/pydantic_ai_adapter.py +420 -0
  111. agent_os/integrations/rate_limiter.py +130 -0
  112. agent_os/integrations/rbac.py +143 -0
  113. agent_os/integrations/registry.py +113 -0
  114. agent_os/integrations/scope_guard.py +303 -0
  115. agent_os/integrations/semantic_kernel_adapter.py +769 -0
  116. agent_os/integrations/smolagents_adapter.py +629 -0
  117. agent_os/integrations/templates.py +178 -0
  118. agent_os/integrations/token_budget.py +134 -0
  119. agent_os/integrations/tool_aliases.py +190 -0
  120. agent_os/integrations/webhooks.py +177 -0
  121. agent_os/lite.py +208 -0
  122. agent_os/mcp_gateway.py +385 -0
  123. agent_os/mcp_message_signer.py +273 -0
  124. agent_os/mcp_protocols.py +161 -0
  125. agent_os/mcp_response_scanner.py +232 -0
  126. agent_os/mcp_security.py +924 -0
  127. agent_os/mcp_session_auth.py +231 -0
  128. agent_os/mcp_sliding_rate_limiter.py +184 -0
  129. agent_os/memory_guard.py +409 -0
  130. agent_os/metrics.py +134 -0
  131. agent_os/mute.py +428 -0
  132. agent_os/mute_agent.py +209 -0
  133. agent_os/policies/__init__.py +77 -0
  134. agent_os/policies/async_evaluator.py +275 -0
  135. agent_os/policies/backends.py +670 -0
  136. agent_os/policies/bridge.py +169 -0
  137. agent_os/policies/budget.py +85 -0
  138. agent_os/policies/cli.py +294 -0
  139. agent_os/policies/conflict_resolution.py +270 -0
  140. agent_os/policies/data_classification.py +252 -0
  141. agent_os/policies/evaluator.py +239 -0
  142. agent_os/policies/policy_schema.json +228 -0
  143. agent_os/policies/rate_limiting.py +145 -0
  144. agent_os/policies/schema.py +115 -0
  145. agent_os/policies/shared.py +331 -0
  146. agent_os/prompt_injection.py +694 -0
  147. agent_os/providers.py +182 -0
  148. agent_os/py.typed +0 -0
  149. agent_os/retry.py +81 -0
  150. agent_os/reversibility.py +251 -0
  151. agent_os/sandbox.py +432 -0
  152. agent_os/sandbox_provider.py +140 -0
  153. agent_os/secure_codegen.py +525 -0
  154. agent_os/security_skills.py +538 -0
  155. agent_os/semantic_policy.py +422 -0
  156. agent_os/server/__init__.py +15 -0
  157. agent_os/server/__main__.py +25 -0
  158. agent_os/server/app.py +277 -0
  159. agent_os/server/models.py +104 -0
  160. agent_os/shift_left_metrics.py +130 -0
  161. agent_os/stateless.py +742 -0
  162. agent_os/supervisor.py +148 -0
  163. agent_os/task_outcome.py +148 -0
  164. agent_os/transparency.py +181 -0
  165. agent_os/trust_root.py +128 -0
  166. agent_os_kernel-3.1.0.dist-info/METADATA +1269 -0
  167. agent_os_kernel-3.1.0.dist-info/RECORD +337 -0
  168. agent_os_kernel-3.1.0.dist-info/WHEEL +4 -0
  169. agent_os_kernel-3.1.0.dist-info/entry_points.txt +2 -0
  170. agent_os_kernel-3.1.0.dist-info/licenses/LICENSE +21 -0
  171. agent_os_observability/__init__.py +27 -0
  172. agent_os_observability/dashboards.py +898 -0
  173. agent_os_observability/metrics.py +398 -0
  174. agent_os_observability/server.py +223 -0
  175. agent_os_observability/tracer.py +232 -0
  176. agent_primitives/__init__.py +24 -0
  177. agent_primitives/failures.py +84 -0
  178. agent_primitives/py.typed +0 -0
  179. amb_core/__init__.py +177 -0
  180. amb_core/adapters/__init__.py +57 -0
  181. amb_core/adapters/aws_sqs_broker.py +376 -0
  182. amb_core/adapters/azure_servicebus_broker.py +340 -0
  183. amb_core/adapters/kafka_broker.py +260 -0
  184. amb_core/adapters/nats_broker.py +285 -0
  185. amb_core/adapters/rabbitmq_broker.py +235 -0
  186. amb_core/adapters/redis_broker.py +262 -0
  187. amb_core/broker.py +145 -0
  188. amb_core/bus.py +481 -0
  189. amb_core/cloudevents.py +509 -0
  190. amb_core/dlq.py +345 -0
  191. amb_core/hf_utils.py +536 -0
  192. amb_core/memory_broker.py +410 -0
  193. amb_core/models.py +141 -0
  194. amb_core/persistence.py +529 -0
  195. amb_core/schema.py +294 -0
  196. amb_core/tracing.py +358 -0
  197. atr/__init__.py +640 -0
  198. atr/access.py +348 -0
  199. atr/composition.py +645 -0
  200. atr/decorator.py +357 -0
  201. atr/executor.py +384 -0
  202. atr/health.py +557 -0
  203. atr/hf_utils.py +449 -0
  204. atr/injection.py +422 -0
  205. atr/metrics.py +440 -0
  206. atr/policies.py +403 -0
  207. atr/py.typed +2 -0
  208. atr/registry.py +452 -0
  209. atr/schema.py +480 -0
  210. atr/tools/safe/__init__.py +75 -0
  211. atr/tools/safe/calculator.py +467 -0
  212. atr/tools/safe/datetime_tool.py +443 -0
  213. atr/tools/safe/file_reader.py +402 -0
  214. atr/tools/safe/http_client.py +316 -0
  215. atr/tools/safe/json_parser.py +374 -0
  216. atr/tools/safe/text_tool.py +537 -0
  217. atr/tools/safe/toolkit.py +175 -0
  218. caas/__init__.py +162 -0
  219. caas/api/__init__.py +7 -0
  220. caas/api/server.py +1328 -0
  221. caas/caching.py +834 -0
  222. caas/cli.py +210 -0
  223. caas/conversation.py +223 -0
  224. caas/decay.py +72 -0
  225. caas/detection/__init__.py +9 -0
  226. caas/detection/detector.py +238 -0
  227. caas/enrichment.py +130 -0
  228. caas/gateway/__init__.py +27 -0
  229. caas/gateway/trust_gateway.py +474 -0
  230. caas/hf_utils.py +479 -0
  231. caas/ingestion/__init__.py +23 -0
  232. caas/ingestion/processors.py +253 -0
  233. caas/ingestion/structure_parser.py +188 -0
  234. caas/models.py +356 -0
  235. caas/pragmatic_truth.py +444 -0
  236. caas/routing/__init__.py +10 -0
  237. caas/routing/heuristic_router.py +58 -0
  238. caas/storage/__init__.py +9 -0
  239. caas/storage/store.py +389 -0
  240. caas/triad.py +213 -0
  241. caas/tuning/__init__.py +9 -0
  242. caas/tuning/tuner.py +329 -0
  243. caas/vfs/__init__.py +14 -0
  244. caas/vfs/filesystem.py +452 -0
  245. cmvk/__init__.py +218 -0
  246. cmvk/audit.py +402 -0
  247. cmvk/benchmarks.py +478 -0
  248. cmvk/constitutional.py +904 -0
  249. cmvk/hf_utils.py +301 -0
  250. cmvk/metrics.py +473 -0
  251. cmvk/profiles.py +300 -0
  252. cmvk/py.typed +0 -0
  253. cmvk/types.py +12 -0
  254. cmvk/verification.py +956 -0
  255. emk/__init__.py +89 -0
  256. emk/causal.py +352 -0
  257. emk/hf_utils.py +421 -0
  258. emk/indexer.py +83 -0
  259. emk/py.typed +0 -0
  260. emk/schema.py +204 -0
  261. emk/sleep_cycle.py +347 -0
  262. emk/store.py +281 -0
  263. iatp/__init__.py +166 -0
  264. iatp/attestation.py +461 -0
  265. iatp/cli.py +317 -0
  266. iatp/hf_utils.py +472 -0
  267. iatp/ipc_pipes.py +580 -0
  268. iatp/main.py +412 -0
  269. iatp/models/__init__.py +447 -0
  270. iatp/policy_engine.py +337 -0
  271. iatp/py.typed +2 -0
  272. iatp/recovery.py +321 -0
  273. iatp/security/__init__.py +270 -0
  274. iatp/sidecar/__init__.py +519 -0
  275. iatp/telemetry/__init__.py +164 -0
  276. iatp/tests/__init__.py +1 -0
  277. iatp/tests/test_attestation.py +370 -0
  278. iatp/tests/test_cli.py +131 -0
  279. iatp/tests/test_ed25519_attestation.py +211 -0
  280. iatp/tests/test_models.py +130 -0
  281. iatp/tests/test_policy_engine.py +347 -0
  282. iatp/tests/test_recovery.py +281 -0
  283. iatp/tests/test_security.py +222 -0
  284. iatp/tests/test_sidecar.py +167 -0
  285. iatp/tests/test_telemetry.py +175 -0
  286. mcp_kernel_server/__init__.py +28 -0
  287. mcp_kernel_server/cli.py +274 -0
  288. mcp_kernel_server/resources.py +217 -0
  289. mcp_kernel_server/server.py +564 -0
  290. mcp_kernel_server/tools.py +1174 -0
  291. mute_agent/__init__.py +68 -0
  292. mute_agent/core/__init__.py +1 -0
  293. mute_agent/core/execution_agent.py +166 -0
  294. mute_agent/core/handshake_protocol.py +201 -0
  295. mute_agent/core/reasoning_agent.py +238 -0
  296. mute_agent/knowledge_graph/__init__.py +1 -0
  297. mute_agent/knowledge_graph/graph_elements.py +65 -0
  298. mute_agent/knowledge_graph/multidimensional_graph.py +170 -0
  299. mute_agent/knowledge_graph/subgraph.py +224 -0
  300. mute_agent/listener/__init__.py +43 -0
  301. mute_agent/listener/adapters/__init__.py +31 -0
  302. mute_agent/listener/adapters/base_adapter.py +189 -0
  303. mute_agent/listener/adapters/caas_adapter.py +344 -0
  304. mute_agent/listener/adapters/control_plane_adapter.py +436 -0
  305. mute_agent/listener/adapters/iatp_adapter.py +332 -0
  306. mute_agent/listener/adapters/scak_adapter.py +251 -0
  307. mute_agent/listener/listener.py +610 -0
  308. mute_agent/listener/state_observer.py +436 -0
  309. mute_agent/listener/threshold_config.py +313 -0
  310. mute_agent/super_system/__init__.py +1 -0
  311. mute_agent/super_system/router.py +204 -0
  312. mute_agent/visualization/__init__.py +10 -0
  313. mute_agent/visualization/graph_debugger.py +502 -0
  314. nexus/README.md +60 -0
  315. nexus/__init__.py +51 -0
  316. nexus/arbiter.py +359 -0
  317. nexus/client.py +466 -0
  318. nexus/dmz.py +444 -0
  319. nexus/escrow.py +430 -0
  320. nexus/exceptions.py +286 -0
  321. nexus/pyproject.toml +36 -0
  322. nexus/registry.py +393 -0
  323. nexus/reputation.py +425 -0
  324. nexus/schemas/__init__.py +51 -0
  325. nexus/schemas/compliance.py +276 -0
  326. nexus/schemas/escrow.py +251 -0
  327. nexus/schemas/manifest.py +225 -0
  328. nexus/schemas/receipt.py +208 -0
  329. nexus/tests/__init__.py +0 -0
  330. nexus/tests/conftest.py +146 -0
  331. nexus/tests/test_arbiter.py +192 -0
  332. nexus/tests/test_dmz.py +194 -0
  333. nexus/tests/test_escrow.py +276 -0
  334. nexus/tests/test_exceptions.py +225 -0
  335. nexus/tests/test_registry.py +232 -0
  336. nexus/tests/test_reputation.py +328 -0
  337. nexus/tests/test_schemas.py +295 -0
@@ -0,0 +1,557 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+
4
+ """
5
+ Time-Travel Debugger - Replay Agent History
6
+
7
+ Feature: "Time-Travel Debugging"
8
+ Problem: Need to understand and debug agent behavior after the fact.
9
+ Solution: Since all communication is on amb (message bus) and all history is in emk (event kernel),
10
+ build a "Replay" tool. "Re-run the last 5 minutes of Agent A's life exactly as it happened."
11
+ Result: Complete observability and debugging capability for agent behavior.
12
+
13
+ This module provides infrastructure to replay agent execution history from
14
+ the audit logs and message history.
15
+ """
16
+
17
+ from typing import Any, Dict, List, Optional, Tuple
18
+ from dataclasses import dataclass, field
19
+ from datetime import datetime, timedelta
20
+ from enum import Enum
21
+ import logging
22
+ import json
23
+
24
+
25
+ class ReplayMode(Enum):
26
+ """Mode for replaying agent history"""
27
+ STEP_BY_STEP = "step_by_step"
28
+ CONTINUOUS = "continuous"
29
+ FAST_FORWARD = "fast_forward"
30
+
31
+
32
+ class ReplayEventType(Enum):
33
+ """Types of events that can be replayed"""
34
+ MESSAGE_SENT = "message_sent"
35
+ MESSAGE_RECEIVED = "message_received"
36
+ TOOL_EXECUTION = "tool_execution"
37
+ POLICY_CHECK = "policy_check"
38
+ STATE_CHANGE = "state_change"
39
+ ERROR = "error"
40
+
41
+
42
+ @dataclass
43
+ class ReplayEvent:
44
+ """An event in the replay timeline"""
45
+ event_id: str
46
+ event_type: ReplayEventType
47
+ timestamp: datetime
48
+ agent_id: str
49
+ data: Dict[str, Any]
50
+ metadata: Dict[str, Any] = field(default_factory=dict)
51
+
52
+
53
+ @dataclass
54
+ class ReplaySession:
55
+ """A replay session for an agent"""
56
+ session_id: str
57
+ agent_id: str
58
+ start_time: datetime
59
+ end_time: datetime
60
+ events: List[ReplayEvent]
61
+ mode: ReplayMode
62
+ current_index: int = 0
63
+ created_at: datetime = field(default_factory=datetime.now)
64
+
65
+
66
+ @dataclass
67
+ class TimeTravelConfig:
68
+ """Configuration for time-travel debugging"""
69
+ enabled: bool = True
70
+ max_replay_duration_minutes: int = 60
71
+ enable_state_snapshots: bool = True
72
+ snapshot_interval_seconds: int = 60
73
+ max_stored_snapshots: int = 100
74
+ enable_replay_cache: bool = True
75
+
76
+
77
+ class TimeTravelDebugger:
78
+ """
79
+ Time-Travel Debugger for replaying agent execution history.
80
+
81
+ This class provides:
82
+ - Replay of agent actions and decisions over a time period
83
+ - Step-by-step or continuous replay modes
84
+ - Integration with FlightRecorder for complete audit trails
85
+ - State snapshot capture for point-in-time restoration
86
+ """
87
+
88
+ def __init__(
89
+ self,
90
+ flight_recorder: Optional[Any] = None,
91
+ config: Optional[TimeTravelConfig] = None
92
+ ):
93
+ """
94
+ Initialize the time-travel debugger.
95
+
96
+ Args:
97
+ flight_recorder: FlightRecorder instance for accessing audit logs
98
+ config: Configuration for time-travel behavior
99
+ """
100
+ self.config = config or TimeTravelConfig()
101
+ self.flight_recorder = flight_recorder
102
+ self.logger = logging.getLogger("TimeTravelDebugger")
103
+
104
+ # Store replay sessions
105
+ self.active_sessions: Dict[str, ReplaySession] = {}
106
+
107
+ # Store state snapshots for time-travel
108
+ self.state_snapshots: Dict[str, List[Dict[str, Any]]] = {}
109
+
110
+ # Cache for replay events
111
+ self.event_cache: Dict[str, List[ReplayEvent]] = {}
112
+
113
+ self.logger.info("TimeTravelDebugger initialized")
114
+
115
+ def capture_state_snapshot(
116
+ self,
117
+ agent_id: str,
118
+ agent_state: Dict[str, Any],
119
+ metadata: Optional[Dict[str, Any]] = None
120
+ ):
121
+ """
122
+ Capture a point-in-time snapshot of agent state.
123
+
124
+ Args:
125
+ agent_id: Agent identifier
126
+ agent_state: Complete agent state to snapshot
127
+ metadata: Optional metadata about the snapshot
128
+ """
129
+ if not self.config.enable_state_snapshots:
130
+ return
131
+
132
+ snapshot = {
133
+ "agent_id": agent_id,
134
+ "timestamp": datetime.now().isoformat(),
135
+ "state": agent_state,
136
+ "metadata": metadata or {}
137
+ }
138
+
139
+ if agent_id not in self.state_snapshots:
140
+ self.state_snapshots[agent_id] = []
141
+
142
+ self.state_snapshots[agent_id].append(snapshot)
143
+
144
+ # Limit number of snapshots
145
+ if len(self.state_snapshots[agent_id]) > self.config.max_stored_snapshots:
146
+ self.state_snapshots[agent_id] = self.state_snapshots[agent_id][-self.config.max_stored_snapshots:]
147
+
148
+ self.logger.debug(f"Captured state snapshot for agent {agent_id}")
149
+
150
+ def get_state_at_time(
151
+ self,
152
+ agent_id: str,
153
+ target_time: datetime
154
+ ) -> Optional[Dict[str, Any]]:
155
+ """
156
+ Get agent state at a specific point in time.
157
+
158
+ Args:
159
+ agent_id: Agent identifier
160
+ target_time: Target timestamp
161
+
162
+ Returns:
163
+ Agent state snapshot closest to the target time, or None
164
+ """
165
+ if agent_id not in self.state_snapshots:
166
+ return None
167
+
168
+ snapshots = self.state_snapshots[agent_id]
169
+
170
+ # Find closest snapshot before or at target time
171
+ closest_snapshot = None
172
+ min_diff = None
173
+
174
+ for snapshot in snapshots:
175
+ snapshot_time = datetime.fromisoformat(snapshot["timestamp"])
176
+ if snapshot_time <= target_time:
177
+ diff = (target_time - snapshot_time).total_seconds()
178
+ if min_diff is None or diff < min_diff:
179
+ min_diff = diff
180
+ closest_snapshot = snapshot
181
+
182
+ return closest_snapshot
183
+
184
+ def collect_events_from_flight_recorder(
185
+ self,
186
+ agent_id: str,
187
+ start_time: datetime,
188
+ end_time: datetime
189
+ ) -> List[ReplayEvent]:
190
+ """
191
+ Collect replay events from FlightRecorder audit logs.
192
+
193
+ Args:
194
+ agent_id: Agent identifier
195
+ start_time: Start of time range
196
+ end_time: End of time range
197
+
198
+ Returns:
199
+ List of replay events in chronological order
200
+ """
201
+ if not self.flight_recorder:
202
+ self.logger.warning("No FlightRecorder available for event collection")
203
+ return []
204
+
205
+ events = []
206
+
207
+ try:
208
+ # Use the FlightRecorder's get_events_in_time_range method
209
+ if hasattr(self.flight_recorder, 'get_events_in_time_range'):
210
+ audit_entries = self.flight_recorder.get_events_in_time_range(
211
+ start_time, end_time, agent_id
212
+ )
213
+ else:
214
+ # Fallback to get_log method
215
+ audit_log = self.flight_recorder.get_log() if hasattr(self.flight_recorder, 'get_log') else []
216
+
217
+ # Filter manually
218
+ audit_entries = []
219
+ for entry in audit_log:
220
+ entry_time = datetime.fromisoformat(entry.get("timestamp", ""))
221
+ agent_match = entry.get("agent_id") == agent_id
222
+
223
+ if start_time <= entry_time <= end_time and agent_match:
224
+ audit_entries.append(entry)
225
+
226
+ # Convert to ReplayEvents
227
+ for entry in audit_entries:
228
+ event = self._convert_audit_entry_to_replay_event(entry)
229
+ if event:
230
+ events.append(event)
231
+
232
+ except Exception as e:
233
+ self.logger.error(f"Error collecting events from FlightRecorder: {e}")
234
+
235
+ # Sort by timestamp
236
+ events.sort(key=lambda e: e.timestamp)
237
+
238
+ return events
239
+
240
+ def _convert_audit_entry_to_replay_event(
241
+ self,
242
+ audit_entry: Dict[str, Any]
243
+ ) -> Optional[ReplayEvent]:
244
+ """Convert an audit log entry to a ReplayEvent"""
245
+ try:
246
+ # FlightRecorder format has: trace_id, timestamp, agent_id, tool_name,
247
+ # tool_args, input_prompt, policy_verdict, violation_reason, result
248
+
249
+ # Determine event type based on policy verdict and tool name
250
+ policy_verdict = audit_entry.get("policy_verdict", "")
251
+ tool_name = audit_entry.get("tool_name", "")
252
+
253
+ # Map to replay event type
254
+ if policy_verdict == "blocked":
255
+ event_type = ReplayEventType.POLICY_CHECK
256
+ elif policy_verdict == "error":
257
+ event_type = ReplayEventType.ERROR
258
+ elif tool_name:
259
+ event_type = ReplayEventType.TOOL_EXECUTION
260
+ else:
261
+ event_type = ReplayEventType.STATE_CHANGE
262
+
263
+ # Parse tool_args if it's JSON string
264
+ tool_args = audit_entry.get("tool_args")
265
+ if tool_args and isinstance(tool_args, str):
266
+ try:
267
+ tool_args = json.loads(tool_args)
268
+ except (json.JSONDecodeError, ValueError) as e:
269
+ self.logger.debug("Could not parse tool_args as JSON: %s", e)
270
+
271
+ # Parse result if it's JSON string
272
+ result = audit_entry.get("result")
273
+ if result and isinstance(result, str):
274
+ try:
275
+ result = json.loads(result)
276
+ except (json.JSONDecodeError, ValueError) as e:
277
+ self.logger.debug("Could not parse result as JSON: %s", e)
278
+
279
+ return ReplayEvent(
280
+ event_id=audit_entry.get("trace_id", str(id(audit_entry))),
281
+ event_type=event_type,
282
+ timestamp=datetime.fromisoformat(audit_entry["timestamp"]),
283
+ agent_id=audit_entry.get("agent_id", ""),
284
+ data={
285
+ "tool_name": tool_name,
286
+ "tool_args": tool_args,
287
+ "input_prompt": audit_entry.get("input_prompt"),
288
+ "policy_verdict": policy_verdict,
289
+ "violation_reason": audit_entry.get("violation_reason"),
290
+ "result": result,
291
+ "execution_time_ms": audit_entry.get("execution_time_ms"),
292
+ },
293
+ metadata={
294
+ "db_id": audit_entry.get("id"),
295
+ "trace_id": audit_entry.get("trace_id")
296
+ }
297
+ )
298
+ except Exception as e:
299
+ self.logger.error(f"Error converting audit entry: {e}")
300
+ return None
301
+
302
+ def create_replay_session(
303
+ self,
304
+ agent_id: str,
305
+ start_time: datetime,
306
+ end_time: datetime,
307
+ mode: ReplayMode = ReplayMode.CONTINUOUS
308
+ ) -> ReplaySession:
309
+ """
310
+ Create a new replay session for an agent.
311
+
312
+ Args:
313
+ agent_id: Agent identifier
314
+ start_time: Start of replay period
315
+ end_time: End of replay period
316
+ mode: Replay mode (step-by-step, continuous, fast-forward)
317
+
318
+ Returns:
319
+ Created ReplaySession
320
+ """
321
+ # Validate time range
322
+ duration = (end_time - start_time).total_seconds() / 60
323
+ if duration > self.config.max_replay_duration_minutes:
324
+ raise ValueError(
325
+ f"Replay duration ({duration} min) exceeds maximum "
326
+ f"({self.config.max_replay_duration_minutes} min)"
327
+ )
328
+
329
+ # Collect events
330
+ events = self.collect_events_from_flight_recorder(agent_id, start_time, end_time)
331
+
332
+ # Create session
333
+ session = ReplaySession(
334
+ session_id=f"replay_{agent_id}_{int(datetime.now().timestamp())}",
335
+ agent_id=agent_id,
336
+ start_time=start_time,
337
+ end_time=end_time,
338
+ events=events,
339
+ mode=mode
340
+ )
341
+
342
+ self.active_sessions[session.session_id] = session
343
+
344
+ self.logger.info(
345
+ f"Created replay session {session.session_id} for agent {agent_id} "
346
+ f"with {len(events)} events from {start_time} to {end_time}"
347
+ )
348
+
349
+ return session
350
+
351
+ def replay_time_window(
352
+ self,
353
+ agent_id: str,
354
+ minutes: int,
355
+ mode: ReplayMode = ReplayMode.CONTINUOUS
356
+ ) -> ReplaySession:
357
+ """
358
+ Replay the last N minutes of an agent's life.
359
+
360
+ Args:
361
+ agent_id: Agent identifier
362
+ minutes: Number of minutes to replay
363
+ mode: Replay mode
364
+
365
+ Returns:
366
+ Created ReplaySession
367
+ """
368
+ end_time = datetime.now()
369
+ start_time = end_time - timedelta(minutes=minutes)
370
+
371
+ return self.create_replay_session(agent_id, start_time, end_time, mode)
372
+
373
+ def replay_agent_history(
374
+ self,
375
+ agent_id: str,
376
+ session_id: Optional[str] = None,
377
+ callback: Optional[callable] = None
378
+ ) -> List[ReplayEvent]:
379
+ """
380
+ Replay agent history, optionally with a callback for each event.
381
+
382
+ Args:
383
+ agent_id: Agent identifier
384
+ session_id: Specific session to replay (uses most recent if None)
385
+ callback: Optional callback function called for each event
386
+
387
+ Returns:
388
+ List of replayed events
389
+ """
390
+ # Find session
391
+ if session_id:
392
+ if session_id not in self.active_sessions:
393
+ raise ValueError(f"Replay session {session_id} not found")
394
+ session = self.active_sessions[session_id]
395
+ else:
396
+ # Find most recent session for this agent
397
+ agent_sessions = [
398
+ s for s in self.active_sessions.values()
399
+ if s.agent_id == agent_id
400
+ ]
401
+ if not agent_sessions:
402
+ raise ValueError(f"No replay sessions found for agent {agent_id}")
403
+ session = max(agent_sessions, key=lambda s: s.created_at)
404
+
405
+ replayed_events = []
406
+
407
+ # Replay based on mode
408
+ if session.mode == ReplayMode.STEP_BY_STEP:
409
+ # Return events one at a time (user must call next_step)
410
+ if session.current_index < len(session.events):
411
+ if callback:
412
+ callback(session.events[session.current_index])
413
+ replayed_events.append(session.events[session.current_index])
414
+ session.current_index += 1
415
+ else:
416
+ # Continuous or fast-forward: replay all events
417
+ for event in session.events:
418
+ replayed_events.append(event)
419
+ if callback:
420
+ callback(event)
421
+ session.current_index += 1
422
+
423
+ return replayed_events
424
+
425
+ def next_step(self, session_id: str) -> Optional[ReplayEvent]:
426
+ """
427
+ Advance to the next event in a step-by-step replay session.
428
+
429
+ Args:
430
+ session_id: Replay session identifier
431
+
432
+ Returns:
433
+ Next event, or None if at end
434
+ """
435
+ if session_id not in self.active_sessions:
436
+ raise ValueError(f"Replay session {session_id} not found")
437
+
438
+ session = self.active_sessions[session_id]
439
+
440
+ if session.current_index >= len(session.events):
441
+ return None
442
+
443
+ event = session.events[session.current_index]
444
+ session.current_index += 1
445
+
446
+ return event
447
+
448
+ def get_session_progress(self, session_id: str) -> Dict[str, Any]:
449
+ """Get progress information for a replay session"""
450
+ if session_id not in self.active_sessions:
451
+ raise ValueError(f"Replay session {session_id} not found")
452
+
453
+ session = self.active_sessions[session_id]
454
+
455
+ return {
456
+ "session_id": session.session_id,
457
+ "agent_id": session.agent_id,
458
+ "total_events": len(session.events),
459
+ "current_index": session.current_index,
460
+ "completed": session.current_index >= len(session.events),
461
+ "progress_percent": (session.current_index / len(session.events) * 100) if session.events else 0,
462
+ "mode": session.mode.value,
463
+ "time_range": {
464
+ "start": session.start_time.isoformat(),
465
+ "end": session.end_time.isoformat()
466
+ }
467
+ }
468
+
469
+ def get_replay_summary(self, session_id: str) -> Dict[str, Any]:
470
+ """Get a summary of a replay session"""
471
+ if session_id not in self.active_sessions:
472
+ raise ValueError(f"Replay session {session_id} not found")
473
+
474
+ session = self.active_sessions[session_id]
475
+
476
+ # Aggregate statistics
477
+ event_type_counts = {}
478
+ for event in session.events:
479
+ event_type = event.event_type.value
480
+ event_type_counts[event_type] = event_type_counts.get(event_type, 0) + 1
481
+
482
+ return {
483
+ "session_id": session.session_id,
484
+ "agent_id": session.agent_id,
485
+ "time_range": {
486
+ "start": session.start_time.isoformat(),
487
+ "end": session.end_time.isoformat(),
488
+ "duration_seconds": (session.end_time - session.start_time).total_seconds()
489
+ },
490
+ "total_events": len(session.events),
491
+ "event_type_breakdown": event_type_counts,
492
+ "mode": session.mode.value,
493
+ "created_at": session.created_at.isoformat()
494
+ }
495
+
496
+ def export_replay_session(
497
+ self,
498
+ session_id: str,
499
+ format: str = "json"
500
+ ) -> str:
501
+ """
502
+ Export a replay session for external analysis.
503
+
504
+ Args:
505
+ session_id: Replay session identifier
506
+ format: Export format (currently only 'json')
507
+
508
+ Returns:
509
+ Serialized replay session
510
+ """
511
+ if session_id not in self.active_sessions:
512
+ raise ValueError(f"Replay session {session_id} not found")
513
+
514
+ session = self.active_sessions[session_id]
515
+
516
+ export_data = {
517
+ "session_id": session.session_id,
518
+ "agent_id": session.agent_id,
519
+ "start_time": session.start_time.isoformat(),
520
+ "end_time": session.end_time.isoformat(),
521
+ "mode": session.mode.value,
522
+ "events": [
523
+ {
524
+ "event_id": e.event_id,
525
+ "event_type": e.event_type.value,
526
+ "timestamp": e.timestamp.isoformat(),
527
+ "agent_id": e.agent_id,
528
+ "data": e.data,
529
+ "metadata": e.metadata
530
+ }
531
+ for e in session.events
532
+ ],
533
+ "summary": self.get_replay_summary(session_id)
534
+ }
535
+
536
+ return json.dumps(export_data, indent=2)
537
+
538
+ def close_session(self, session_id: str):
539
+ """Close and remove a replay session"""
540
+ if session_id in self.active_sessions:
541
+ del self.active_sessions[session_id]
542
+ self.logger.info(f"Closed replay session {session_id}")
543
+
544
+ def get_statistics(self) -> Dict[str, Any]:
545
+ """Get statistics about time-travel debugging"""
546
+ total_snapshots = sum(len(snapshots) for snapshots in self.state_snapshots.values())
547
+
548
+ return {
549
+ "active_replay_sessions": len(self.active_sessions),
550
+ "total_state_snapshots": total_snapshots,
551
+ "agents_with_snapshots": len(self.state_snapshots),
552
+ "config": {
553
+ "enabled": self.config.enabled,
554
+ "max_replay_duration_minutes": self.config.max_replay_duration_minutes,
555
+ "enable_state_snapshots": self.config.enable_state_snapshots
556
+ }
557
+ }