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,436 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ State Observer for Listener Agent
5
+
6
+ Provides passive observation capabilities for monitoring graph states
7
+ without interfering with normal operations.
8
+
9
+ This observer is designed to:
10
+ 1. Collect metrics from the knowledge graph
11
+ 2. Track state changes over time
12
+ 3. Calculate derived metrics for threshold evaluation
13
+ """
14
+
15
+ from typing import Dict, Any, Optional, List, Callable
16
+ from dataclasses import dataclass, field
17
+ from datetime import datetime, timedelta
18
+ from collections import deque
19
+ from enum import Enum, auto
20
+
21
+ from ..knowledge_graph.multidimensional_graph import MultidimensionalKnowledgeGraph
22
+ from ..knowledge_graph.graph_elements import EdgeType
23
+ from ..core.handshake_protocol import HandshakeProtocol, HandshakeState
24
+ from ..super_system.router import SuperSystemRouter
25
+
26
+
27
+ class MetricType(Enum):
28
+ """Types of metrics the observer can collect."""
29
+
30
+ # Graph metrics
31
+ NODE_COUNT = auto()
32
+ EDGE_COUNT = auto()
33
+ DIMENSION_COUNT = auto()
34
+ ACTION_SPACE_SIZE = auto()
35
+ CONFLICT_EDGE_COUNT = auto()
36
+
37
+ # Session metrics
38
+ ACTIVE_SESSIONS = auto()
39
+ COMPLETED_SESSIONS = auto()
40
+ FAILED_SESSIONS = auto()
41
+ REJECTED_SESSIONS = auto()
42
+
43
+ # Performance metrics
44
+ LAST_TRAVERSAL_TIME_MS = auto()
45
+ AVG_TRAVERSAL_TIME_MS = auto()
46
+
47
+ # Derived metrics
48
+ REJECTION_RATE = auto()
49
+ CONFLICT_RATIO = auto()
50
+ SESSION_SUCCESS_RATE = auto()
51
+
52
+
53
+ @dataclass
54
+ class MetricSample:
55
+ """A single metric sample with timestamp."""
56
+
57
+ metric_type: MetricType
58
+ value: float
59
+ timestamp: datetime = field(default_factory=datetime.now)
60
+ metadata: Dict[str, Any] = field(default_factory=dict)
61
+
62
+
63
+ @dataclass
64
+ class ObservationResult:
65
+ """Result of a state observation cycle."""
66
+
67
+ timestamp: datetime
68
+ metrics: Dict[MetricType, float]
69
+ derived_metrics: Dict[str, float]
70
+ anomalies_detected: List[str]
71
+ graph_snapshot: Optional[Dict[str, Any]] = None
72
+
73
+ def to_threshold_metrics(self) -> Dict:
74
+ """
75
+ Convert observation result to threshold-compatible metrics.
76
+
77
+ Maps MetricType to ThresholdType for threshold evaluation.
78
+ """
79
+ from .threshold_config import ThresholdType
80
+
81
+ mapping = {
82
+ "constraint_violation_count": ThresholdType.CONSTRAINT_VIOLATION_COUNT,
83
+ "dimension_conflict_ratio": ThresholdType.DIMENSION_CONFLICT_RATIO,
84
+ "action_rejection_rate": ThresholdType.ACTION_REJECTION_RATE,
85
+ "context_drift": ThresholdType.CONTEXT_DRIFT_MAXIMUM,
86
+ "ambiguity_score": ThresholdType.AMBIGUITY_SCORE_MAXIMUM,
87
+ "traversal_latency_ms": ThresholdType.GRAPH_TRAVERSAL_LATENCY_MS,
88
+ }
89
+
90
+ result = {}
91
+ for key, threshold_type in mapping.items():
92
+ if key in self.derived_metrics:
93
+ result[threshold_type] = self.derived_metrics[key]
94
+
95
+ return result
96
+
97
+
98
+ class StateObserver:
99
+ """
100
+ Passive state observer for the Listener Agent.
101
+
102
+ Collects metrics from the knowledge graph, handshake protocol,
103
+ and router without interfering with their operation.
104
+
105
+ This class implements the Observer pattern - it watches but does not act.
106
+ The Listener Agent is responsible for deciding when to intervene.
107
+ """
108
+
109
+ # Maximum samples to retain in memory per metric
110
+ MAX_SAMPLES_PER_METRIC = 1000
111
+
112
+ def __init__(
113
+ self,
114
+ knowledge_graph: MultidimensionalKnowledgeGraph,
115
+ protocol: HandshakeProtocol,
116
+ router: SuperSystemRouter,
117
+ sample_window_seconds: float = 60.0,
118
+ ):
119
+ """
120
+ Initialize the state observer.
121
+
122
+ Args:
123
+ knowledge_graph: The graph to observe
124
+ protocol: The handshake protocol to observe
125
+ router: The super system router to observe
126
+ sample_window_seconds: Window for calculating rolling metrics
127
+ """
128
+ self.knowledge_graph = knowledge_graph
129
+ self.protocol = protocol
130
+ self.router = router
131
+ self.sample_window = timedelta(seconds=sample_window_seconds)
132
+
133
+ # Sample storage - bounded deques for memory safety
134
+ self._samples: Dict[MetricType, deque] = {
135
+ metric_type: deque(maxlen=self.MAX_SAMPLES_PER_METRIC)
136
+ for metric_type in MetricType
137
+ }
138
+
139
+ # Observation history
140
+ self._observations: deque = deque(maxlen=1000)
141
+
142
+ # Custom metric collectors
143
+ self._custom_collectors: Dict[str, Callable[[], float]] = {}
144
+
145
+ # Baseline metrics for anomaly detection
146
+ self._baselines: Dict[MetricType, float] = {}
147
+
148
+ def observe(self, context: Optional[Dict[str, Any]] = None) -> ObservationResult:
149
+ """
150
+ Perform a single observation cycle.
151
+
152
+ Collects all metrics from the observed components and calculates
153
+ derived metrics for threshold evaluation.
154
+
155
+ Args:
156
+ context: Optional context to include in observation
157
+
158
+ Returns:
159
+ ObservationResult with all collected metrics
160
+ """
161
+ timestamp = datetime.now()
162
+ metrics = {}
163
+ anomalies = []
164
+
165
+ # Collect graph metrics
166
+ metrics.update(self._collect_graph_metrics())
167
+
168
+ # Collect session metrics
169
+ metrics.update(self._collect_session_metrics())
170
+
171
+ # Collect performance metrics
172
+ metrics.update(self._collect_performance_metrics())
173
+
174
+ # Store samples
175
+ for metric_type, value in metrics.items():
176
+ sample = MetricSample(metric_type=metric_type, value=value, timestamp=timestamp)
177
+ self._samples[metric_type].append(sample)
178
+
179
+ # Calculate derived metrics
180
+ derived_metrics = self._calculate_derived_metrics(metrics, context)
181
+
182
+ # Detect anomalies
183
+ anomalies = self._detect_anomalies(metrics)
184
+
185
+ # Create observation result
186
+ result = ObservationResult(
187
+ timestamp=timestamp,
188
+ metrics={k: v for k, v in metrics.items()},
189
+ derived_metrics=derived_metrics,
190
+ anomalies_detected=anomalies,
191
+ graph_snapshot=self._create_graph_snapshot() if context else None,
192
+ )
193
+
194
+ # Store observation
195
+ self._observations.append(result)
196
+
197
+ return result
198
+
199
+ def _collect_graph_metrics(self) -> Dict[MetricType, float]:
200
+ """Collect metrics from the knowledge graph."""
201
+ metrics = {}
202
+
203
+ # Count dimensions
204
+ metrics[MetricType.DIMENSION_COUNT] = float(len(self.knowledge_graph.dimensions))
205
+
206
+ # Count total nodes and edges across all subgraphs
207
+ total_nodes = 0
208
+ total_edges = 0
209
+ conflict_edges = 0
210
+
211
+ for dim_name, subgraph in self.knowledge_graph.subgraphs.items():
212
+ total_nodes += len(subgraph.nodes)
213
+ for edges in subgraph._adjacency_list.values():
214
+ total_edges += len(edges)
215
+ conflict_edges += sum(
216
+ 1 for e in edges if e.edge_type == EdgeType.CONFLICTS_WITH
217
+ )
218
+
219
+ metrics[MetricType.NODE_COUNT] = float(total_nodes)
220
+ metrics[MetricType.EDGE_COUNT] = float(total_edges)
221
+ metrics[MetricType.CONFLICT_EDGE_COUNT] = float(conflict_edges)
222
+
223
+ return metrics
224
+
225
+ def _collect_session_metrics(self) -> Dict[MetricType, float]:
226
+ """Collect metrics from the handshake protocol."""
227
+ metrics = {}
228
+
229
+ sessions = self.protocol.sessions
230
+
231
+ active = sum(
232
+ 1 for s in sessions.values()
233
+ if s.state in [HandshakeState.INITIATED, HandshakeState.NEGOTIATING,
234
+ HandshakeState.VALIDATED, HandshakeState.ACCEPTED,
235
+ HandshakeState.EXECUTING]
236
+ )
237
+ completed = sum(
238
+ 1 for s in sessions.values()
239
+ if s.state == HandshakeState.COMPLETED
240
+ )
241
+ failed = sum(
242
+ 1 for s in sessions.values()
243
+ if s.state == HandshakeState.FAILED
244
+ )
245
+ rejected = sum(
246
+ 1 for s in sessions.values()
247
+ if s.state == HandshakeState.REJECTED
248
+ )
249
+
250
+ metrics[MetricType.ACTIVE_SESSIONS] = float(active)
251
+ metrics[MetricType.COMPLETED_SESSIONS] = float(completed)
252
+ metrics[MetricType.FAILED_SESSIONS] = float(failed)
253
+ metrics[MetricType.REJECTED_SESSIONS] = float(rejected)
254
+
255
+ return metrics
256
+
257
+ def _collect_performance_metrics(self) -> Dict[MetricType, float]:
258
+ """Collect performance-related metrics."""
259
+ metrics = {}
260
+
261
+ # Get routing statistics
262
+ routing_stats = self.router.get_routing_statistics()
263
+
264
+ # Use routing history for latency estimation
265
+ # In production, this would integrate with actual timing measurements
266
+ metrics[MetricType.LAST_TRAVERSAL_TIME_MS] = 0.0
267
+ metrics[MetricType.AVG_TRAVERSAL_TIME_MS] = 0.0
268
+
269
+ # Action space size from last routing
270
+ if self.router.routing_history:
271
+ last_routing = self.router.routing_history[-1]
272
+ metrics[MetricType.ACTION_SPACE_SIZE] = float(
273
+ len(last_routing.pruned_action_space)
274
+ )
275
+ else:
276
+ metrics[MetricType.ACTION_SPACE_SIZE] = 0.0
277
+
278
+ return metrics
279
+
280
+ def _calculate_derived_metrics(
281
+ self,
282
+ metrics: Dict[MetricType, float],
283
+ context: Optional[Dict[str, Any]] = None
284
+ ) -> Dict[str, float]:
285
+ """Calculate derived metrics from raw metrics."""
286
+ derived = {}
287
+
288
+ # Rejection rate
289
+ total_sessions = (
290
+ metrics.get(MetricType.COMPLETED_SESSIONS, 0) +
291
+ metrics.get(MetricType.FAILED_SESSIONS, 0) +
292
+ metrics.get(MetricType.REJECTED_SESSIONS, 0)
293
+ )
294
+ if total_sessions > 0:
295
+ derived["action_rejection_rate"] = (
296
+ metrics.get(MetricType.REJECTED_SESSIONS, 0) / total_sessions
297
+ )
298
+ else:
299
+ derived["action_rejection_rate"] = 0.0
300
+
301
+ # Conflict ratio
302
+ total_edges = metrics.get(MetricType.EDGE_COUNT, 0)
303
+ if total_edges > 0:
304
+ derived["dimension_conflict_ratio"] = (
305
+ metrics.get(MetricType.CONFLICT_EDGE_COUNT, 0) / total_edges
306
+ )
307
+ else:
308
+ derived["dimension_conflict_ratio"] = 0.0
309
+
310
+ # Session success rate
311
+ if total_sessions > 0:
312
+ derived["session_success_rate"] = (
313
+ metrics.get(MetricType.COMPLETED_SESSIONS, 0) / total_sessions
314
+ )
315
+ else:
316
+ derived["session_success_rate"] = 1.0
317
+
318
+ # Constraint violation count (from recent history)
319
+ derived["constraint_violation_count"] = self._count_recent_violations()
320
+
321
+ # Placeholder for context-aware metrics
322
+ # These would integrate with caas (context-as-a-service) in production
323
+ derived["context_drift"] = 0.0
324
+ derived["ambiguity_score"] = 0.0
325
+ derived["traversal_latency_ms"] = metrics.get(MetricType.AVG_TRAVERSAL_TIME_MS, 0.0)
326
+
327
+ return derived
328
+
329
+ def _count_recent_violations(self) -> float:
330
+ """Count constraint violations in the recent observation window."""
331
+ cutoff = datetime.now() - self.sample_window
332
+
333
+ # Count rejected sessions in window
334
+ violations = 0
335
+ for session in self.protocol.sessions.values():
336
+ if session.state == HandshakeState.REJECTED:
337
+ if session.updated_at >= cutoff:
338
+ violations += 1
339
+
340
+ return float(violations)
341
+
342
+ def _detect_anomalies(self, metrics: Dict[MetricType, float]) -> List[str]:
343
+ """Detect anomalies based on baseline comparison."""
344
+ anomalies = []
345
+
346
+ for metric_type, value in metrics.items():
347
+ if metric_type in self._baselines:
348
+ baseline = self._baselines[metric_type]
349
+ # Simple anomaly detection: >2x deviation from baseline
350
+ if baseline > 0 and abs(value - baseline) / baseline > 2.0:
351
+ anomalies.append(
352
+ f"Anomaly in {metric_type.name}: "
353
+ f"current={value:.2f}, baseline={baseline:.2f}"
354
+ )
355
+
356
+ return anomalies
357
+
358
+ def _create_graph_snapshot(self) -> Dict[str, Any]:
359
+ """Create a lightweight snapshot of graph state."""
360
+ snapshot = {
361
+ "dimensions": list(self.knowledge_graph.dimensions.keys()),
362
+ "node_counts": {},
363
+ "edge_counts": {},
364
+ }
365
+
366
+ for dim_name, subgraph in self.knowledge_graph.subgraphs.items():
367
+ snapshot["node_counts"][dim_name] = len(subgraph._nodes)
368
+ snapshot["edge_counts"][dim_name] = sum(
369
+ len(edges) for edges in subgraph._adjacency_list.values()
370
+ )
371
+
372
+ return snapshot
373
+
374
+ def set_baseline(self, metric_type: MetricType, value: float) -> None:
375
+ """Set a baseline value for anomaly detection."""
376
+ self._baselines[metric_type] = value
377
+
378
+ def calibrate_baselines(self, num_samples: int = 10) -> None:
379
+ """
380
+ Calibrate baselines by averaging recent samples.
381
+
382
+ Call this during a known-good operational period to establish
383
+ baseline metrics for anomaly detection.
384
+ """
385
+ for metric_type, samples in self._samples.items():
386
+ if len(samples) >= num_samples:
387
+ recent = list(samples)[-num_samples:]
388
+ avg_value = sum(s.value for s in recent) / len(recent)
389
+ self._baselines[metric_type] = avg_value
390
+
391
+ def register_custom_collector(
392
+ self,
393
+ name: str,
394
+ collector: Callable[[], float]
395
+ ) -> None:
396
+ """
397
+ Register a custom metric collector.
398
+
399
+ Args:
400
+ name: Unique name for the custom metric
401
+ collector: Function that returns the metric value
402
+ """
403
+ self._custom_collectors[name] = collector
404
+
405
+ def get_metric_history(
406
+ self,
407
+ metric_type: MetricType,
408
+ window_seconds: Optional[float] = None
409
+ ) -> List[MetricSample]:
410
+ """
411
+ Get historical samples for a metric.
412
+
413
+ Args:
414
+ metric_type: The metric to retrieve
415
+ window_seconds: Optional time window (None = all samples)
416
+
417
+ Returns:
418
+ List of metric samples
419
+ """
420
+ samples = list(self._samples.get(metric_type, []))
421
+
422
+ if window_seconds is not None:
423
+ cutoff = datetime.now() - timedelta(seconds=window_seconds)
424
+ samples = [s for s in samples if s.timestamp >= cutoff]
425
+
426
+ return samples
427
+
428
+ def get_observation_history(
429
+ self,
430
+ count: Optional[int] = None
431
+ ) -> List[ObservationResult]:
432
+ """Get recent observation results."""
433
+ observations = list(self._observations)
434
+ if count is not None:
435
+ observations = observations[-count:]
436
+ return observations