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
iatp/ipc_pipes.py ADDED
@@ -0,0 +1,580 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Typed IPC Pipes - Inter-Agent Communication with Policy Enforcement.
5
+
6
+ This module implements typed pipes for agent-to-agent communication,
7
+ inspired by UNIX pipes but with policy enforcement at the kernel level.
8
+
9
+ Instead of "Workflow Builders" (bloat), real engineers use pipes:
10
+ AgentA | PolicyCheck | AgentB
11
+
12
+ Design Philosophy:
13
+ - Type safety: Only matching types can connect
14
+ - Policy enforcement: Every message passes through policy check
15
+ - Backpressure: Slow consumers don't crash fast producers
16
+ - Audit trail: All pipe traffic is logged to flight recorder
17
+
18
+ Example:
19
+ # Create a typed pipe
20
+ pipe = TypedPipe[ResearchResult, SummaryRequest]("research-to-summary")
21
+
22
+ # Connect agents via pipe with policy enforcement
23
+ pipeline = (
24
+ research_agent
25
+ | PolicyCheckPipe(allowed_types=[ResearchResult])
26
+ | summary_agent
27
+ )
28
+
29
+ # Execute pipeline
30
+ result = await pipeline.execute(input_data)
31
+
32
+ This is the IATP extension for secure inter-agent communication.
33
+ """
34
+
35
+ from abc import ABC, abstractmethod
36
+ from dataclasses import dataclass, field
37
+ from datetime import datetime, timezone
38
+ from enum import Enum, auto
39
+ from typing import (
40
+ Any, AsyncIterator, Callable, Dict, Generic, List, Optional,
41
+ TypeVar, Union, Awaitable, Protocol, runtime_checkable
42
+ )
43
+ import asyncio
44
+ import hashlib
45
+ import json
46
+ import logging
47
+ from queue import Queue
48
+ from threading import Lock
49
+
50
+ logger = logging.getLogger(__name__)
51
+
52
+
53
+ # Type variables for generic pipes
54
+ T_In = TypeVar("T_In")
55
+ T_Out = TypeVar("T_Out")
56
+ T = TypeVar("T")
57
+
58
+
59
+ class PipeState(Enum):
60
+ """State of a pipe."""
61
+ CREATED = auto()
62
+ OPEN = auto()
63
+ FLOWING = auto()
64
+ BLOCKED = auto() # Backpressure
65
+ CLOSED = auto()
66
+ ERROR = auto()
67
+
68
+
69
+ @dataclass
70
+ class PipeMessage(Generic[T]):
71
+ """
72
+ A message flowing through a pipe.
73
+
74
+ Every message carries metadata for policy enforcement and auditing.
75
+ """
76
+ payload: T
77
+ message_id: str = field(default_factory=lambda: hashlib.sha256(
78
+ str(datetime.now(timezone.utc).timestamp()).encode()
79
+ ).hexdigest()[:16])
80
+ timestamp: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
81
+ source_agent: Optional[str] = None
82
+ target_agent: Optional[str] = None
83
+ trace_id: Optional[str] = None
84
+
85
+ # Policy enforcement metadata
86
+ policy_checked: bool = False
87
+ policy_result: Optional[str] = None
88
+
89
+ # Type information for runtime checking
90
+ payload_type: Optional[str] = None
91
+
92
+ def __post_init__(self):
93
+ if self.payload_type is None:
94
+ self.payload_type = type(self.payload).__name__
95
+
96
+ def to_dict(self) -> Dict[str, Any]:
97
+ return {
98
+ "message_id": self.message_id,
99
+ "timestamp": self.timestamp.isoformat(),
100
+ "source_agent": self.source_agent,
101
+ "target_agent": self.target_agent,
102
+ "trace_id": self.trace_id,
103
+ "payload_type": self.payload_type,
104
+ "policy_checked": self.policy_checked,
105
+ "policy_result": self.policy_result,
106
+ }
107
+
108
+
109
+ @dataclass
110
+ class PipeConfig:
111
+ """Configuration for a typed pipe."""
112
+ name: str
113
+ buffer_size: int = 100
114
+ timeout_seconds: float = 30.0
115
+ require_policy_check: bool = True
116
+ allowed_payload_types: List[str] = field(default_factory=list)
117
+ max_message_size_bytes: int = 10 * 1024 * 1024 # 10MB default
118
+ enable_compression: bool = False
119
+ enable_encryption: bool = False
120
+
121
+
122
+ @runtime_checkable
123
+ class PipeEndpoint(Protocol[T]):
124
+ """Protocol for pipe endpoints (can send or receive)."""
125
+
126
+ async def send(self, message: PipeMessage[T]) -> bool:
127
+ """Send a message through the pipe."""
128
+ ...
129
+
130
+ async def receive(self) -> Optional[PipeMessage[T]]:
131
+ """Receive a message from the pipe."""
132
+ ...
133
+
134
+
135
+ class TypedPipe(Generic[T_In, T_Out]):
136
+ """
137
+ A typed pipe for inter-agent communication.
138
+
139
+ Type parameters:
140
+ T_In: Type of messages this pipe accepts
141
+ T_Out: Type of messages this pipe produces
142
+
143
+ Example:
144
+ pipe = TypedPipe[ResearchQuery, ResearchResult]("research-pipe")
145
+ await pipe.send(PipeMessage(ResearchQuery(topic="AI Safety")))
146
+ result = await pipe.receive()
147
+ """
148
+
149
+ def __init__(
150
+ self,
151
+ name: str,
152
+ config: Optional[PipeConfig] = None,
153
+ transform: Optional[Callable[[T_In], T_Out]] = None,
154
+ ):
155
+ self.name = name
156
+ self.config = config or PipeConfig(name=name)
157
+ self._transform = transform
158
+
159
+ self._state = PipeState.CREATED
160
+ self._buffer: asyncio.Queue[PipeMessage] = asyncio.Queue(
161
+ maxsize=self.config.buffer_size
162
+ )
163
+ self._lock = asyncio.Lock()
164
+ self._message_count = 0
165
+ self._error_count = 0
166
+
167
+ # Policy enforcement callback
168
+ self._policy_check: Optional[Callable[[PipeMessage], Awaitable[bool]]] = None
169
+
170
+ # Audit callback
171
+ self._audit_callback: Optional[Callable[[PipeMessage, str], None]] = None
172
+
173
+ @property
174
+ def state(self) -> PipeState:
175
+ return self._state
176
+
177
+ def open(self) -> None:
178
+ """Open the pipe for communication."""
179
+ self._state = PipeState.OPEN
180
+ logger.info(f"[Pipe] {self.name} opened")
181
+
182
+ def close(self) -> None:
183
+ """Close the pipe."""
184
+ self._state = PipeState.CLOSED
185
+ logger.info(f"[Pipe] {self.name} closed")
186
+
187
+ def set_policy_check(
188
+ self,
189
+ check: Callable[[PipeMessage], Awaitable[bool]]
190
+ ) -> None:
191
+ """Set the policy check callback."""
192
+ self._policy_check = check
193
+
194
+ def set_audit_callback(
195
+ self,
196
+ callback: Callable[[PipeMessage, str], None]
197
+ ) -> None:
198
+ """Set the audit callback for message logging."""
199
+ self._audit_callback = callback
200
+
201
+ async def send(self, message: PipeMessage[T_In]) -> bool:
202
+ """
203
+ Send a message through the pipe.
204
+
205
+ Returns True if message was sent, False if rejected by policy.
206
+ """
207
+ if self._state not in (PipeState.OPEN, PipeState.FLOWING):
208
+ raise RuntimeError(f"Pipe {self.name} is not open (state: {self._state})")
209
+
210
+ # Policy check
211
+ if self.config.require_policy_check:
212
+ if self._policy_check:
213
+ try:
214
+ allowed = await self._policy_check(message)
215
+ message.policy_checked = True
216
+ message.policy_result = "ALLOWED" if allowed else "DENIED"
217
+
218
+ if not allowed:
219
+ logger.warning(
220
+ f"[Pipe] {self.name} rejected message {message.message_id} "
221
+ f"by policy"
222
+ )
223
+ if self._audit_callback:
224
+ self._audit_callback(message, "POLICY_DENIED")
225
+ return False
226
+ except Exception as e:
227
+ logger.error(f"[Pipe] Policy check failed: {e}")
228
+ message.policy_result = f"ERROR: {e}"
229
+ self._error_count += 1
230
+ return False
231
+ else:
232
+ logger.warning(f"[Pipe] {self.name} has no policy check configured")
233
+
234
+ # Type checking
235
+ if self.config.allowed_payload_types:
236
+ if message.payload_type not in self.config.allowed_payload_types:
237
+ logger.error(
238
+ f"[Pipe] {self.name} rejected message with type "
239
+ f"{message.payload_type} (allowed: {self.config.allowed_payload_types})"
240
+ )
241
+ return False
242
+
243
+ # Apply transform if configured
244
+ if self._transform:
245
+ try:
246
+ transformed_payload = self._transform(message.payload)
247
+ message = PipeMessage(
248
+ payload=transformed_payload,
249
+ message_id=message.message_id,
250
+ timestamp=message.timestamp,
251
+ source_agent=message.source_agent,
252
+ target_agent=message.target_agent,
253
+ trace_id=message.trace_id,
254
+ policy_checked=message.policy_checked,
255
+ policy_result=message.policy_result,
256
+ )
257
+ except Exception as e:
258
+ logger.error(f"[Pipe] Transform failed: {e}")
259
+ self._error_count += 1
260
+ return False
261
+
262
+ # Queue message (with backpressure)
263
+ try:
264
+ await asyncio.wait_for(
265
+ self._buffer.put(message),
266
+ timeout=self.config.timeout_seconds
267
+ )
268
+ self._message_count += 1
269
+ self._state = PipeState.FLOWING
270
+
271
+ if self._audit_callback:
272
+ self._audit_callback(message, "SENT")
273
+
274
+ return True
275
+ except asyncio.TimeoutError:
276
+ logger.warning(f"[Pipe] {self.name} timeout - backpressure")
277
+ self._state = PipeState.BLOCKED
278
+ return False
279
+
280
+ async def receive(self) -> Optional[PipeMessage[T_Out]]:
281
+ """
282
+ Receive a message from the pipe.
283
+
284
+ Returns None if pipe is closed or timeout occurs.
285
+ """
286
+ if self._state == PipeState.CLOSED:
287
+ return None
288
+
289
+ try:
290
+ message = await asyncio.wait_for(
291
+ self._buffer.get(),
292
+ timeout=self.config.timeout_seconds
293
+ )
294
+
295
+ if self._audit_callback:
296
+ self._audit_callback(message, "RECEIVED")
297
+
298
+ return message
299
+ except asyncio.TimeoutError:
300
+ return None
301
+
302
+ def get_stats(self) -> Dict[str, Any]:
303
+ """Get pipe statistics."""
304
+ return {
305
+ "name": self.name,
306
+ "state": self._state.name,
307
+ "message_count": self._message_count,
308
+ "error_count": self._error_count,
309
+ "buffer_size": self._buffer.qsize(),
310
+ "buffer_max": self.config.buffer_size,
311
+ }
312
+
313
+
314
+ class PolicyCheckPipe(TypedPipe[T, T]):
315
+ """
316
+ A pipe that only performs policy checking (pass-through).
317
+
318
+ Use this in pipelines to enforce policy at specific points:
319
+ agent_a | PolicyCheckPipe(policy_engine) | agent_b
320
+ """
321
+
322
+ def __init__(
323
+ self,
324
+ name: str = "policy-check",
325
+ policy_engine: Optional[Any] = None, # PolicyEngine from control plane
326
+ allowed_types: Optional[List[str]] = None,
327
+ ):
328
+ config = PipeConfig(
329
+ name=name,
330
+ require_policy_check=True,
331
+ allowed_payload_types=allowed_types or [],
332
+ )
333
+ super().__init__(name, config)
334
+ self._policy_engine = policy_engine
335
+
336
+ # Set up policy check
337
+ if policy_engine:
338
+ self.set_policy_check(self._check_with_engine)
339
+
340
+ async def _check_with_engine(self, message: PipeMessage) -> bool:
341
+ """Check message against policy engine."""
342
+ if not self._policy_engine:
343
+ return True
344
+
345
+ # Integration with control plane PolicyEngine
346
+ try:
347
+ # This would integrate with the actual policy engine
348
+ # For now, always allow
349
+ return True
350
+ except Exception as e:
351
+ logger.error(f"[PolicyCheckPipe] Engine check failed: {e}")
352
+ return False
353
+
354
+
355
+ @runtime_checkable
356
+ class PipelineStage(Protocol):
357
+ """Protocol for pipeline stages."""
358
+
359
+ async def process(self, message: PipeMessage) -> Optional[PipeMessage]:
360
+ """Process a message and optionally produce output."""
361
+ ...
362
+
363
+ def __or__(self, other: "PipelineStage") -> "Pipeline":
364
+ """Support pipe operator: stage1 | stage2"""
365
+ ...
366
+
367
+
368
+ class AgentPipelineStage:
369
+ """
370
+ Wraps an agent as a pipeline stage.
371
+
372
+ Example:
373
+ stage = AgentPipelineStage(my_agent, input_type="Query", output_type="Response")
374
+ """
375
+
376
+ def __init__(
377
+ self,
378
+ agent: Any,
379
+ agent_id: str,
380
+ process_method: str = "process",
381
+ input_type: Optional[str] = None,
382
+ output_type: Optional[str] = None,
383
+ ):
384
+ self.agent = agent
385
+ self.agent_id = agent_id
386
+ self._process_method = process_method
387
+ self.input_type = input_type
388
+ self.output_type = output_type
389
+
390
+ async def process(self, message: PipeMessage) -> Optional[PipeMessage]:
391
+ """Process a message through the agent."""
392
+ method = getattr(self.agent, self._process_method, None)
393
+ if not method:
394
+ raise AttributeError(
395
+ f"Agent {self.agent_id} has no method '{self._process_method}'"
396
+ )
397
+
398
+ # Call agent's process method
399
+ if asyncio.iscoroutinefunction(method):
400
+ result = await method(message.payload)
401
+ else:
402
+ result = method(message.payload)
403
+
404
+ if result is None:
405
+ return None
406
+
407
+ return PipeMessage(
408
+ payload=result,
409
+ source_agent=self.agent_id,
410
+ trace_id=message.trace_id,
411
+ )
412
+
413
+ def __or__(self, other: "AgentPipelineStage") -> "Pipeline":
414
+ """Support pipe operator."""
415
+ return Pipeline([self, other])
416
+
417
+
418
+ class Pipeline:
419
+ """
420
+ A pipeline of connected stages.
421
+
422
+ Example:
423
+ pipeline = Pipeline([
424
+ AgentPipelineStage(research_agent, "research"),
425
+ PolicyCheckPipe(),
426
+ AgentPipelineStage(summary_agent, "summary"),
427
+ ])
428
+
429
+ result = await pipeline.execute(input_message)
430
+ """
431
+
432
+ def __init__(
433
+ self,
434
+ stages: Optional[List[Union[AgentPipelineStage, TypedPipe]]] = None,
435
+ name: str = "pipeline",
436
+ ):
437
+ self.name = name
438
+ self.stages: List[Union[AgentPipelineStage, TypedPipe]] = stages or []
439
+ self._trace_id: Optional[str] = None
440
+
441
+ def add_stage(self, stage: Union[AgentPipelineStage, TypedPipe]) -> "Pipeline":
442
+ """Add a stage to the pipeline."""
443
+ self.stages.append(stage)
444
+ return self
445
+
446
+ def __or__(self, other: Union[AgentPipelineStage, TypedPipe, "Pipeline"]) -> "Pipeline":
447
+ """Support pipe operator: pipeline | stage"""
448
+ if isinstance(other, Pipeline):
449
+ return Pipeline(self.stages + other.stages, self.name)
450
+ else:
451
+ return Pipeline(self.stages + [other], self.name)
452
+
453
+ async def execute(
454
+ self,
455
+ input_data: Any,
456
+ trace_id: Optional[str] = None,
457
+ ) -> Optional[PipeMessage]:
458
+ """
459
+ Execute the pipeline with input data.
460
+
461
+ Returns the final message, or None if pipeline filtered it out.
462
+ """
463
+ self._trace_id = trace_id or hashlib.sha256(
464
+ str(datetime.now(timezone.utc).timestamp()).encode()
465
+ ).hexdigest()[:16]
466
+
467
+ # Create initial message
468
+ current_message = PipeMessage(
469
+ payload=input_data,
470
+ trace_id=self._trace_id,
471
+ )
472
+
473
+ logger.info(f"[Pipeline] {self.name} executing with trace {self._trace_id}")
474
+
475
+ for i, stage in enumerate(self.stages):
476
+ stage_name = getattr(stage, 'name', None) or getattr(stage, 'agent_id', f'stage-{i}')
477
+ logger.debug(f"[Pipeline] Processing stage: {stage_name}")
478
+
479
+ if isinstance(stage, TypedPipe):
480
+ # For pipes, send and receive
481
+ stage.open()
482
+ if not await stage.send(current_message):
483
+ logger.warning(f"[Pipeline] Stage {stage_name} rejected message")
484
+ return None
485
+ current_message = await stage.receive()
486
+ stage.close()
487
+ elif isinstance(stage, AgentPipelineStage):
488
+ # For agent stages, process directly
489
+ current_message = await stage.process(current_message)
490
+ else:
491
+ # Generic stage with process method
492
+ if hasattr(stage, 'process'):
493
+ if asyncio.iscoroutinefunction(stage.process):
494
+ current_message = await stage.process(current_message)
495
+ else:
496
+ current_message = stage.process(current_message)
497
+
498
+ if current_message is None:
499
+ logger.info(f"[Pipeline] Stage {stage_name} filtered out message")
500
+ return None
501
+
502
+ # Update target agent for next stage
503
+ if i + 1 < len(self.stages):
504
+ next_stage = self.stages[i + 1]
505
+ current_message.target_agent = getattr(
506
+ next_stage, 'agent_id',
507
+ getattr(next_stage, 'name', None)
508
+ )
509
+
510
+ logger.info(f"[Pipeline] {self.name} completed trace {self._trace_id}")
511
+ return current_message
512
+
513
+ async def execute_streaming(
514
+ self,
515
+ input_data: Any,
516
+ trace_id: Optional[str] = None,
517
+ ) -> AsyncIterator[PipeMessage]:
518
+ """
519
+ Execute pipeline with streaming output.
520
+
521
+ Yields messages as they flow through stages.
522
+ """
523
+ self._trace_id = trace_id or hashlib.sha256(
524
+ str(datetime.now(timezone.utc).timestamp()).encode()
525
+ ).hexdigest()[:16]
526
+
527
+ current_message = PipeMessage(
528
+ payload=input_data,
529
+ trace_id=self._trace_id,
530
+ )
531
+
532
+ yield current_message
533
+
534
+ for stage in self.stages:
535
+ if isinstance(stage, TypedPipe):
536
+ stage.open()
537
+ await stage.send(current_message)
538
+ current_message = await stage.receive()
539
+ stage.close()
540
+ elif hasattr(stage, 'process'):
541
+ if asyncio.iscoroutinefunction(stage.process):
542
+ current_message = await stage.process(current_message)
543
+ else:
544
+ current_message = stage.process(current_message)
545
+
546
+ if current_message:
547
+ yield current_message
548
+ else:
549
+ return
550
+
551
+
552
+ # ========== Convenience Functions ==========
553
+
554
+ def create_pipeline(*stages: Union[AgentPipelineStage, TypedPipe]) -> Pipeline:
555
+ """Create a pipeline from stages."""
556
+ return Pipeline(list(stages))
557
+
558
+
559
+ def pipe_agents(
560
+ source_agent: Any,
561
+ source_id: str,
562
+ target_agent: Any,
563
+ target_id: str,
564
+ policy_engine: Optional[Any] = None,
565
+ ) -> Pipeline:
566
+ """
567
+ Create a simple two-agent pipeline with policy check.
568
+
569
+ Example:
570
+ pipeline = pipe_agents(
571
+ research_agent, "research",
572
+ summary_agent, "summary",
573
+ policy_engine=my_policy_engine
574
+ )
575
+ """
576
+ return Pipeline([
577
+ AgentPipelineStage(source_agent, source_id),
578
+ PolicyCheckPipe(policy_engine=policy_engine),
579
+ AgentPipelineStage(target_agent, target_id),
580
+ ])