agent-os-kernel 1.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.
- agent_os/__init__.py +303 -0
- agent_os/cli.py +44 -0
- agent_os/integrations/__init__.py +17 -0
- agent_os/integrations/autogen_adapter.py +144 -0
- agent_os/integrations/base.py +133 -0
- agent_os/integrations/crewai_adapter.py +121 -0
- agent_os/integrations/langchain_adapter.py +157 -0
- agent_os_kernel-1.1.0.dist-info/METADATA +400 -0
- agent_os_kernel-1.1.0.dist-info/RECORD +12 -0
- agent_os_kernel-1.1.0.dist-info/WHEEL +4 -0
- agent_os_kernel-1.1.0.dist-info/entry_points.txt +3 -0
- agent_os_kernel-1.1.0.dist-info/licenses/LICENSE +21 -0
agent_os/__init__.py
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent OS - A Safety-First Kernel for Autonomous AI Agents
|
|
3
|
+
|
|
4
|
+
Agent OS provides POSIX-inspired primitives for AI agent systems with
|
|
5
|
+
a 0% policy violation guarantee through kernel-level enforcement.
|
|
6
|
+
|
|
7
|
+
Architecture Layers:
|
|
8
|
+
Layer 1 - Primitives: Base models, verification, context, memory
|
|
9
|
+
Layer 2 - Infrastructure: Trust protocol, message bus, tool registry
|
|
10
|
+
Layer 3 - Framework: Control plane, signals, VFS, kernel space
|
|
11
|
+
Layer 4 - Intelligence: Self-correction, reasoning/execution split
|
|
12
|
+
|
|
13
|
+
Quick Start:
|
|
14
|
+
>>> from agent_os import KernelSpace, AgentSignal, AgentVFS
|
|
15
|
+
>>> kernel = KernelSpace()
|
|
16
|
+
>>> ctx = kernel.create_agent_context("agent-001")
|
|
17
|
+
>>> await ctx.write("/mem/working/task.txt", "Hello World")
|
|
18
|
+
|
|
19
|
+
Installation:
|
|
20
|
+
pip install agent-os[full] # Everything
|
|
21
|
+
pip install agent-os[core] # Primitives + Control Plane
|
|
22
|
+
pip install agent-os # Minimal (just base)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
__version__ = "1.0.0"
|
|
26
|
+
__author__ = "Imran Siddique"
|
|
27
|
+
__license__ = "MIT"
|
|
28
|
+
|
|
29
|
+
# ============================================================================
|
|
30
|
+
# Layer 1: Primitives
|
|
31
|
+
# ============================================================================
|
|
32
|
+
|
|
33
|
+
# Agent Primitives - Base failure models
|
|
34
|
+
try:
|
|
35
|
+
from agent_primitives import (
|
|
36
|
+
AgentFailure,
|
|
37
|
+
FailureType,
|
|
38
|
+
FailureSeverity,
|
|
39
|
+
)
|
|
40
|
+
_PRIMITIVES_AVAILABLE = True
|
|
41
|
+
except ImportError:
|
|
42
|
+
_PRIMITIVES_AVAILABLE = False
|
|
43
|
+
|
|
44
|
+
# CMVK - Cross-Model Verification Kernel
|
|
45
|
+
try:
|
|
46
|
+
from cmvk import (
|
|
47
|
+
DriftDetector,
|
|
48
|
+
SemanticDrift,
|
|
49
|
+
verify_outputs,
|
|
50
|
+
)
|
|
51
|
+
_CMVK_AVAILABLE = True
|
|
52
|
+
except ImportError:
|
|
53
|
+
_CMVK_AVAILABLE = False
|
|
54
|
+
|
|
55
|
+
# CaaS - Context as a Service
|
|
56
|
+
try:
|
|
57
|
+
from caas import (
|
|
58
|
+
ContextPipeline,
|
|
59
|
+
RAGContext,
|
|
60
|
+
)
|
|
61
|
+
_CAAS_AVAILABLE = True
|
|
62
|
+
except ImportError:
|
|
63
|
+
_CAAS_AVAILABLE = False
|
|
64
|
+
|
|
65
|
+
# EMK - Episodic Memory Kernel
|
|
66
|
+
try:
|
|
67
|
+
from emk import (
|
|
68
|
+
EpisodicMemory,
|
|
69
|
+
Episode,
|
|
70
|
+
MemoryStore,
|
|
71
|
+
)
|
|
72
|
+
_EMK_AVAILABLE = True
|
|
73
|
+
except ImportError:
|
|
74
|
+
_EMK_AVAILABLE = False
|
|
75
|
+
|
|
76
|
+
# ============================================================================
|
|
77
|
+
# Layer 2: Infrastructure
|
|
78
|
+
# ============================================================================
|
|
79
|
+
|
|
80
|
+
# IATP - Inter-Agent Trust Protocol
|
|
81
|
+
try:
|
|
82
|
+
from iatp import (
|
|
83
|
+
CapabilityManifest,
|
|
84
|
+
TrustLevel,
|
|
85
|
+
SidecarProxy,
|
|
86
|
+
TypedPipe,
|
|
87
|
+
Pipeline,
|
|
88
|
+
PipeMessage,
|
|
89
|
+
PolicyCheckPipe,
|
|
90
|
+
)
|
|
91
|
+
_IATP_AVAILABLE = True
|
|
92
|
+
except ImportError:
|
|
93
|
+
_IATP_AVAILABLE = False
|
|
94
|
+
|
|
95
|
+
# AMB - Agent Message Bus
|
|
96
|
+
try:
|
|
97
|
+
from amb_core import (
|
|
98
|
+
MessageBus,
|
|
99
|
+
Message,
|
|
100
|
+
Topic,
|
|
101
|
+
)
|
|
102
|
+
_AMB_AVAILABLE = True
|
|
103
|
+
except ImportError:
|
|
104
|
+
_AMB_AVAILABLE = False
|
|
105
|
+
|
|
106
|
+
# ATR - Agent Tool Registry
|
|
107
|
+
try:
|
|
108
|
+
from atr import (
|
|
109
|
+
ToolRegistry,
|
|
110
|
+
Tool,
|
|
111
|
+
ToolExecutor,
|
|
112
|
+
)
|
|
113
|
+
_ATR_AVAILABLE = True
|
|
114
|
+
except ImportError:
|
|
115
|
+
_ATR_AVAILABLE = False
|
|
116
|
+
|
|
117
|
+
# ============================================================================
|
|
118
|
+
# Layer 3: Framework (Control Plane)
|
|
119
|
+
# ============================================================================
|
|
120
|
+
|
|
121
|
+
try:
|
|
122
|
+
from agent_control_plane import (
|
|
123
|
+
# Main Interface
|
|
124
|
+
AgentControlPlane,
|
|
125
|
+
create_control_plane,
|
|
126
|
+
|
|
127
|
+
# Kernel Architecture (v0.3.0)
|
|
128
|
+
AgentSignal,
|
|
129
|
+
SignalDispatcher,
|
|
130
|
+
AgentKernelPanic,
|
|
131
|
+
SignalAwareAgent,
|
|
132
|
+
kill_agent,
|
|
133
|
+
pause_agent,
|
|
134
|
+
resume_agent,
|
|
135
|
+
policy_violation,
|
|
136
|
+
|
|
137
|
+
# Agent VFS
|
|
138
|
+
AgentVFS,
|
|
139
|
+
VFSBackend,
|
|
140
|
+
MemoryBackend,
|
|
141
|
+
FileMode,
|
|
142
|
+
create_agent_vfs,
|
|
143
|
+
|
|
144
|
+
# Kernel/User Space
|
|
145
|
+
KernelSpace,
|
|
146
|
+
AgentContext,
|
|
147
|
+
ProtectionRing,
|
|
148
|
+
SyscallType,
|
|
149
|
+
SyscallRequest,
|
|
150
|
+
SyscallResult,
|
|
151
|
+
KernelState,
|
|
152
|
+
user_space_execution,
|
|
153
|
+
create_kernel,
|
|
154
|
+
|
|
155
|
+
# Policy Engine
|
|
156
|
+
PolicyEngine,
|
|
157
|
+
PolicyRule,
|
|
158
|
+
|
|
159
|
+
# Flight Recorder
|
|
160
|
+
FlightRecorder,
|
|
161
|
+
|
|
162
|
+
# Execution
|
|
163
|
+
ExecutionEngine,
|
|
164
|
+
ExecutionStatus,
|
|
165
|
+
)
|
|
166
|
+
_CONTROL_PLANE_AVAILABLE = True
|
|
167
|
+
except ImportError:
|
|
168
|
+
_CONTROL_PLANE_AVAILABLE = False
|
|
169
|
+
|
|
170
|
+
# ============================================================================
|
|
171
|
+
# Layer 4: Intelligence
|
|
172
|
+
# ============================================================================
|
|
173
|
+
|
|
174
|
+
# SCAK - Self-Correcting Agent Kernel
|
|
175
|
+
try:
|
|
176
|
+
from agent_kernel import (
|
|
177
|
+
SelfCorrectingKernel,
|
|
178
|
+
LazinessDetector,
|
|
179
|
+
DifferentialAuditor,
|
|
180
|
+
)
|
|
181
|
+
_SCAK_AVAILABLE = True
|
|
182
|
+
except ImportError:
|
|
183
|
+
_SCAK_AVAILABLE = False
|
|
184
|
+
|
|
185
|
+
# Mute Agent
|
|
186
|
+
try:
|
|
187
|
+
from mute_agent import (
|
|
188
|
+
MuteAgent,
|
|
189
|
+
ReasoningAgent,
|
|
190
|
+
ExecutionAgent,
|
|
191
|
+
)
|
|
192
|
+
_MUTE_AGENT_AVAILABLE = True
|
|
193
|
+
except ImportError:
|
|
194
|
+
_MUTE_AGENT_AVAILABLE = False
|
|
195
|
+
|
|
196
|
+
# ============================================================================
|
|
197
|
+
# Availability Flags
|
|
198
|
+
# ============================================================================
|
|
199
|
+
|
|
200
|
+
AVAILABLE_PACKAGES = {
|
|
201
|
+
"primitives": _PRIMITIVES_AVAILABLE if '_PRIMITIVES_AVAILABLE' in dir() else False,
|
|
202
|
+
"cmvk": _CMVK_AVAILABLE if '_CMVK_AVAILABLE' in dir() else False,
|
|
203
|
+
"caas": _CAAS_AVAILABLE if '_CAAS_AVAILABLE' in dir() else False,
|
|
204
|
+
"emk": _EMK_AVAILABLE if '_EMK_AVAILABLE' in dir() else False,
|
|
205
|
+
"iatp": _IATP_AVAILABLE if '_IATP_AVAILABLE' in dir() else False,
|
|
206
|
+
"amb": _AMB_AVAILABLE if '_AMB_AVAILABLE' in dir() else False,
|
|
207
|
+
"atr": _ATR_AVAILABLE if '_ATR_AVAILABLE' in dir() else False,
|
|
208
|
+
"control_plane": _CONTROL_PLANE_AVAILABLE if '_CONTROL_PLANE_AVAILABLE' in dir() else False,
|
|
209
|
+
"scak": _SCAK_AVAILABLE if '_SCAK_AVAILABLE' in dir() else False,
|
|
210
|
+
"mute_agent": _MUTE_AGENT_AVAILABLE if '_MUTE_AGENT_AVAILABLE' in dir() else False,
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def check_installation():
|
|
215
|
+
"""Check which Agent OS packages are installed."""
|
|
216
|
+
print("Agent OS Installation Status:")
|
|
217
|
+
print("=" * 40)
|
|
218
|
+
for pkg, available in AVAILABLE_PACKAGES.items():
|
|
219
|
+
status = "✓ Installed" if available else "✗ Not installed"
|
|
220
|
+
print(f" {pkg:15} {status}")
|
|
221
|
+
print("=" * 40)
|
|
222
|
+
print(f"\nInstall missing packages with:")
|
|
223
|
+
print(" pip install agent-os[full]")
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
# ============================================================================
|
|
227
|
+
# Public API
|
|
228
|
+
# ============================================================================
|
|
229
|
+
|
|
230
|
+
__all__ = [
|
|
231
|
+
# Metadata
|
|
232
|
+
"__version__",
|
|
233
|
+
"__author__",
|
|
234
|
+
"AVAILABLE_PACKAGES",
|
|
235
|
+
"check_installation",
|
|
236
|
+
|
|
237
|
+
# Layer 1: Primitives
|
|
238
|
+
"AgentFailure",
|
|
239
|
+
"FailureType",
|
|
240
|
+
"FailureSeverity",
|
|
241
|
+
"DriftDetector",
|
|
242
|
+
"SemanticDrift",
|
|
243
|
+
"verify_outputs",
|
|
244
|
+
"ContextPipeline",
|
|
245
|
+
"RAGContext",
|
|
246
|
+
"EpisodicMemory",
|
|
247
|
+
"Episode",
|
|
248
|
+
"MemoryStore",
|
|
249
|
+
|
|
250
|
+
# Layer 2: Infrastructure
|
|
251
|
+
"CapabilityManifest",
|
|
252
|
+
"TrustLevel",
|
|
253
|
+
"SidecarProxy",
|
|
254
|
+
"TypedPipe",
|
|
255
|
+
"Pipeline",
|
|
256
|
+
"PipeMessage",
|
|
257
|
+
"PolicyCheckPipe",
|
|
258
|
+
"MessageBus",
|
|
259
|
+
"Message",
|
|
260
|
+
"Topic",
|
|
261
|
+
"ToolRegistry",
|
|
262
|
+
"Tool",
|
|
263
|
+
"ToolExecutor",
|
|
264
|
+
|
|
265
|
+
# Layer 3: Framework
|
|
266
|
+
"AgentControlPlane",
|
|
267
|
+
"create_control_plane",
|
|
268
|
+
"AgentSignal",
|
|
269
|
+
"SignalDispatcher",
|
|
270
|
+
"AgentKernelPanic",
|
|
271
|
+
"SignalAwareAgent",
|
|
272
|
+
"kill_agent",
|
|
273
|
+
"pause_agent",
|
|
274
|
+
"resume_agent",
|
|
275
|
+
"policy_violation",
|
|
276
|
+
"AgentVFS",
|
|
277
|
+
"VFSBackend",
|
|
278
|
+
"MemoryBackend",
|
|
279
|
+
"FileMode",
|
|
280
|
+
"create_agent_vfs",
|
|
281
|
+
"KernelSpace",
|
|
282
|
+
"AgentContext",
|
|
283
|
+
"ProtectionRing",
|
|
284
|
+
"SyscallType",
|
|
285
|
+
"SyscallRequest",
|
|
286
|
+
"SyscallResult",
|
|
287
|
+
"KernelState",
|
|
288
|
+
"user_space_execution",
|
|
289
|
+
"create_kernel",
|
|
290
|
+
"PolicyEngine",
|
|
291
|
+
"PolicyRule",
|
|
292
|
+
"FlightRecorder",
|
|
293
|
+
"ExecutionEngine",
|
|
294
|
+
"ExecutionStatus",
|
|
295
|
+
|
|
296
|
+
# Layer 4: Intelligence
|
|
297
|
+
"SelfCorrectingKernel",
|
|
298
|
+
"LazinessDetector",
|
|
299
|
+
"DifferentialAuditor",
|
|
300
|
+
"MuteAgent",
|
|
301
|
+
"ReasoningAgent",
|
|
302
|
+
"ExecutionAgent",
|
|
303
|
+
]
|
agent_os/cli.py
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent OS CLI - Command line interface for Agent OS
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
agentctl status # Check installation status
|
|
6
|
+
agentctl kernel start # Start kernel (future)
|
|
7
|
+
agentctl agent list # List agents (future)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import sys
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def main():
|
|
15
|
+
"""Main entry point for Agent OS CLI."""
|
|
16
|
+
parser = argparse.ArgumentParser(
|
|
17
|
+
prog="agentctl",
|
|
18
|
+
description="Agent OS - A Safety-First Kernel for Autonomous AI Agents",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
subparsers = parser.add_subparsers(dest="command", help="Commands")
|
|
22
|
+
|
|
23
|
+
# Status command
|
|
24
|
+
status_parser = subparsers.add_parser("status", help="Check installation status")
|
|
25
|
+
|
|
26
|
+
# Version command
|
|
27
|
+
version_parser = subparsers.add_parser("version", help="Show version")
|
|
28
|
+
|
|
29
|
+
# Parse args
|
|
30
|
+
args = parser.parse_args()
|
|
31
|
+
|
|
32
|
+
if args.command == "status":
|
|
33
|
+
from agent_os import check_installation
|
|
34
|
+
check_installation()
|
|
35
|
+
elif args.command == "version":
|
|
36
|
+
from agent_os import __version__
|
|
37
|
+
print(f"Agent OS v{__version__}")
|
|
38
|
+
else:
|
|
39
|
+
parser.print_help()
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
if __name__ == "__main__":
|
|
44
|
+
main()
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent OS Integrations
|
|
3
|
+
|
|
4
|
+
Adapters to wrap existing agent frameworks with Agent OS governance.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .langchain_adapter import LangChainKernel
|
|
8
|
+
from .crewai_adapter import CrewAIKernel
|
|
9
|
+
from .autogen_adapter import AutoGenKernel
|
|
10
|
+
from .base import BaseIntegration
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"LangChainKernel",
|
|
14
|
+
"CrewAIKernel",
|
|
15
|
+
"AutoGenKernel",
|
|
16
|
+
"BaseIntegration",
|
|
17
|
+
]
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AutoGen Integration
|
|
3
|
+
|
|
4
|
+
Wraps Microsoft AutoGen agents with Agent OS governance.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from agent_os.integrations import AutoGenKernel
|
|
8
|
+
|
|
9
|
+
kernel = AutoGenKernel()
|
|
10
|
+
kernel.govern(agent1, agent2, agent3)
|
|
11
|
+
|
|
12
|
+
# Now all conversations are governed
|
|
13
|
+
agent1.initiate_chat(agent2, message="...")
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Any, Optional, List
|
|
17
|
+
|
|
18
|
+
from .base import BaseIntegration, GovernancePolicy, ExecutionContext
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AutoGenKernel(BaseIntegration):
|
|
22
|
+
"""
|
|
23
|
+
AutoGen adapter for Agent OS.
|
|
24
|
+
|
|
25
|
+
Supports:
|
|
26
|
+
- AssistantAgent
|
|
27
|
+
- UserProxyAgent
|
|
28
|
+
- GroupChat
|
|
29
|
+
- Conversation flows
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, policy: Optional[GovernancePolicy] = None):
|
|
33
|
+
super().__init__(policy)
|
|
34
|
+
self._governed_agents: dict[str, Any] = {}
|
|
35
|
+
|
|
36
|
+
def wrap(self, agent: Any) -> Any:
|
|
37
|
+
"""Wrap a single AutoGen agent"""
|
|
38
|
+
return self.govern(agent)[0]
|
|
39
|
+
|
|
40
|
+
def govern(self, *agents: Any) -> List[Any]:
|
|
41
|
+
"""
|
|
42
|
+
Add governance to multiple AutoGen agents.
|
|
43
|
+
|
|
44
|
+
Intercepts:
|
|
45
|
+
- initiate_chat()
|
|
46
|
+
- generate_reply()
|
|
47
|
+
- receive()
|
|
48
|
+
- send()
|
|
49
|
+
"""
|
|
50
|
+
governed = []
|
|
51
|
+
|
|
52
|
+
for agent in agents:
|
|
53
|
+
agent_id = getattr(agent, 'name', f"autogen-{id(agent)}")
|
|
54
|
+
ctx = self.create_context(agent_id)
|
|
55
|
+
|
|
56
|
+
# Store reference
|
|
57
|
+
self._governed_agents[agent_id] = agent
|
|
58
|
+
|
|
59
|
+
# Wrap key methods
|
|
60
|
+
self._wrap_initiate_chat(agent, ctx)
|
|
61
|
+
self._wrap_generate_reply(agent, ctx)
|
|
62
|
+
self._wrap_receive(agent, ctx)
|
|
63
|
+
|
|
64
|
+
governed.append(agent)
|
|
65
|
+
|
|
66
|
+
return governed
|
|
67
|
+
|
|
68
|
+
def _wrap_initiate_chat(self, agent: Any, ctx: ExecutionContext):
|
|
69
|
+
"""Wrap initiate_chat method"""
|
|
70
|
+
if not hasattr(agent, 'initiate_chat'):
|
|
71
|
+
return
|
|
72
|
+
|
|
73
|
+
original = agent.initiate_chat
|
|
74
|
+
kernel = self
|
|
75
|
+
|
|
76
|
+
def governed_initiate_chat(recipient, message=None, **kwargs):
|
|
77
|
+
allowed, reason = kernel.pre_execute(ctx, {"recipient": str(recipient), "message": message})
|
|
78
|
+
if not allowed:
|
|
79
|
+
from .langchain_adapter import PolicyViolationError
|
|
80
|
+
raise PolicyViolationError(reason)
|
|
81
|
+
|
|
82
|
+
result = original(recipient, message=message, **kwargs)
|
|
83
|
+
|
|
84
|
+
kernel.post_execute(ctx, result)
|
|
85
|
+
return result
|
|
86
|
+
|
|
87
|
+
agent.initiate_chat = governed_initiate_chat
|
|
88
|
+
|
|
89
|
+
def _wrap_generate_reply(self, agent: Any, ctx: ExecutionContext):
|
|
90
|
+
"""Wrap generate_reply method"""
|
|
91
|
+
if not hasattr(agent, 'generate_reply'):
|
|
92
|
+
return
|
|
93
|
+
|
|
94
|
+
original = agent.generate_reply
|
|
95
|
+
kernel = self
|
|
96
|
+
|
|
97
|
+
def governed_generate_reply(messages=None, sender=None, **kwargs):
|
|
98
|
+
allowed, reason = kernel.pre_execute(ctx, {"messages": messages, "sender": str(sender)})
|
|
99
|
+
if not allowed:
|
|
100
|
+
return f"[BLOCKED: {reason}]"
|
|
101
|
+
|
|
102
|
+
result = original(messages=messages, sender=sender, **kwargs)
|
|
103
|
+
|
|
104
|
+
valid, reason = kernel.post_execute(ctx, result)
|
|
105
|
+
if not valid:
|
|
106
|
+
return f"[BLOCKED: {reason}]"
|
|
107
|
+
|
|
108
|
+
return result
|
|
109
|
+
|
|
110
|
+
agent.generate_reply = governed_generate_reply
|
|
111
|
+
|
|
112
|
+
def _wrap_receive(self, agent: Any, ctx: ExecutionContext):
|
|
113
|
+
"""Wrap receive method"""
|
|
114
|
+
if not hasattr(agent, 'receive'):
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
original = agent.receive
|
|
118
|
+
kernel = self
|
|
119
|
+
|
|
120
|
+
def governed_receive(message, sender, **kwargs):
|
|
121
|
+
allowed, reason = kernel.pre_execute(ctx, {"message": message, "sender": str(sender)})
|
|
122
|
+
if not allowed:
|
|
123
|
+
from .langchain_adapter import PolicyViolationError
|
|
124
|
+
raise PolicyViolationError(reason)
|
|
125
|
+
|
|
126
|
+
result = original(message, sender, **kwargs)
|
|
127
|
+
|
|
128
|
+
kernel.post_execute(ctx, result)
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
agent.receive = governed_receive
|
|
132
|
+
|
|
133
|
+
def unwrap(self, governed_agent: Any) -> Any:
|
|
134
|
+
"""Note: AutoGen agents are modified in-place, can't easily unwrap"""
|
|
135
|
+
raise NotImplementedError(
|
|
136
|
+
"AutoGen agents are governed in-place. "
|
|
137
|
+
"Create a new agent instance if you need ungoverned access."
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Convenience function
|
|
142
|
+
def govern(*agents: Any, policy: Optional[GovernancePolicy] = None) -> List[Any]:
|
|
143
|
+
"""Quick governance for AutoGen agents"""
|
|
144
|
+
return AutoGenKernel(policy).govern(*agents)
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base Integration Interface
|
|
3
|
+
|
|
4
|
+
All framework adapters inherit from this base class.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from abc import ABC, abstractmethod
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Any, Callable, Optional
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class GovernancePolicy:
|
|
15
|
+
"""Policy configuration for governed agents"""
|
|
16
|
+
max_tokens: int = 4096
|
|
17
|
+
max_tool_calls: int = 10
|
|
18
|
+
allowed_tools: list[str] = field(default_factory=list)
|
|
19
|
+
blocked_patterns: list[str] = field(default_factory=list)
|
|
20
|
+
require_human_approval: bool = False
|
|
21
|
+
timeout_seconds: int = 300
|
|
22
|
+
|
|
23
|
+
# Safety thresholds
|
|
24
|
+
confidence_threshold: float = 0.8
|
|
25
|
+
drift_threshold: float = 0.15
|
|
26
|
+
|
|
27
|
+
# Audit settings
|
|
28
|
+
log_all_calls: bool = True
|
|
29
|
+
checkpoint_frequency: int = 5 # Every N calls
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class ExecutionContext:
|
|
34
|
+
"""Context passed through the governance layer"""
|
|
35
|
+
agent_id: str
|
|
36
|
+
session_id: str
|
|
37
|
+
policy: GovernancePolicy
|
|
38
|
+
start_time: datetime = field(default_factory=datetime.now)
|
|
39
|
+
call_count: int = 0
|
|
40
|
+
tool_calls: list[dict] = field(default_factory=list)
|
|
41
|
+
checkpoints: list[str] = field(default_factory=list)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class BaseIntegration(ABC):
|
|
45
|
+
"""
|
|
46
|
+
Base class for framework integrations.
|
|
47
|
+
|
|
48
|
+
Wraps any agent framework with Agent OS governance:
|
|
49
|
+
- Pre-execution policy checks
|
|
50
|
+
- Post-execution validation
|
|
51
|
+
- Flight recording
|
|
52
|
+
- Signal handling
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(self, policy: Optional[GovernancePolicy] = None):
|
|
56
|
+
self.policy = policy or GovernancePolicy()
|
|
57
|
+
self.contexts: dict[str, ExecutionContext] = {}
|
|
58
|
+
self._signal_handlers: dict[str, Callable] = {}
|
|
59
|
+
|
|
60
|
+
@abstractmethod
|
|
61
|
+
def wrap(self, agent: Any) -> Any:
|
|
62
|
+
"""
|
|
63
|
+
Wrap an agent with governance.
|
|
64
|
+
|
|
65
|
+
Returns a governed version of the agent that:
|
|
66
|
+
- Enforces policy on all operations
|
|
67
|
+
- Records execution to flight recorder
|
|
68
|
+
- Responds to signals (SIGSTOP, SIGKILL, etc.)
|
|
69
|
+
"""
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
@abstractmethod
|
|
73
|
+
def unwrap(self, governed_agent: Any) -> Any:
|
|
74
|
+
"""Remove governance wrapper and return original agent"""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def create_context(self, agent_id: str) -> ExecutionContext:
|
|
78
|
+
"""Create execution context for an agent"""
|
|
79
|
+
from uuid import uuid4
|
|
80
|
+
ctx = ExecutionContext(
|
|
81
|
+
agent_id=agent_id,
|
|
82
|
+
session_id=str(uuid4())[:8],
|
|
83
|
+
policy=self.policy
|
|
84
|
+
)
|
|
85
|
+
self.contexts[agent_id] = ctx
|
|
86
|
+
return ctx
|
|
87
|
+
|
|
88
|
+
def pre_execute(self, ctx: ExecutionContext, input_data: Any) -> tuple[bool, Optional[str]]:
|
|
89
|
+
"""
|
|
90
|
+
Pre-execution policy check.
|
|
91
|
+
|
|
92
|
+
Returns (allowed, reason) tuple.
|
|
93
|
+
"""
|
|
94
|
+
# Check call count
|
|
95
|
+
if ctx.call_count >= self.policy.max_tool_calls:
|
|
96
|
+
return False, f"Max tool calls exceeded ({self.policy.max_tool_calls})"
|
|
97
|
+
|
|
98
|
+
# Check timeout
|
|
99
|
+
elapsed = (datetime.now() - ctx.start_time).total_seconds()
|
|
100
|
+
if elapsed > self.policy.timeout_seconds:
|
|
101
|
+
return False, f"Timeout exceeded ({self.policy.timeout_seconds}s)"
|
|
102
|
+
|
|
103
|
+
# Check blocked patterns
|
|
104
|
+
input_str = str(input_data)
|
|
105
|
+
for pattern in self.policy.blocked_patterns:
|
|
106
|
+
if pattern.lower() in input_str.lower():
|
|
107
|
+
return False, f"Blocked pattern detected: {pattern}"
|
|
108
|
+
|
|
109
|
+
return True, None
|
|
110
|
+
|
|
111
|
+
def post_execute(self, ctx: ExecutionContext, output_data: Any) -> tuple[bool, Optional[str]]:
|
|
112
|
+
"""
|
|
113
|
+
Post-execution validation.
|
|
114
|
+
|
|
115
|
+
Returns (valid, reason) tuple.
|
|
116
|
+
"""
|
|
117
|
+
ctx.call_count += 1
|
|
118
|
+
|
|
119
|
+
# Checkpoint if needed
|
|
120
|
+
if ctx.call_count % self.policy.checkpoint_frequency == 0:
|
|
121
|
+
checkpoint_id = f"checkpoint-{ctx.call_count}"
|
|
122
|
+
ctx.checkpoints.append(checkpoint_id)
|
|
123
|
+
|
|
124
|
+
return True, None
|
|
125
|
+
|
|
126
|
+
def on_signal(self, signal: str, handler: Callable):
|
|
127
|
+
"""Register a signal handler"""
|
|
128
|
+
self._signal_handlers[signal] = handler
|
|
129
|
+
|
|
130
|
+
def signal(self, agent_id: str, signal: str):
|
|
131
|
+
"""Send signal to agent"""
|
|
132
|
+
if signal in self._signal_handlers:
|
|
133
|
+
self._signal_handlers[signal](agent_id)
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CrewAI Integration
|
|
3
|
+
|
|
4
|
+
Wraps CrewAI crews and agents with Agent OS governance.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from agent_os.integrations import CrewAIKernel
|
|
8
|
+
|
|
9
|
+
kernel = CrewAIKernel()
|
|
10
|
+
governed_crew = kernel.wrap(my_crew)
|
|
11
|
+
|
|
12
|
+
# Now all crew executions go through Agent OS
|
|
13
|
+
result = governed_crew.kickoff()
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Any, Optional
|
|
17
|
+
|
|
18
|
+
from .base import BaseIntegration, GovernancePolicy, ExecutionContext
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CrewAIKernel(BaseIntegration):
|
|
22
|
+
"""
|
|
23
|
+
CrewAI adapter for Agent OS.
|
|
24
|
+
|
|
25
|
+
Supports:
|
|
26
|
+
- Crew (kickoff, kickoff_async)
|
|
27
|
+
- Individual agents within crews
|
|
28
|
+
- Task execution monitoring
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(self, policy: Optional[GovernancePolicy] = None):
|
|
32
|
+
super().__init__(policy)
|
|
33
|
+
self._wrapped_crews: dict[int, Any] = {}
|
|
34
|
+
|
|
35
|
+
def wrap(self, crew: Any) -> Any:
|
|
36
|
+
"""
|
|
37
|
+
Wrap a CrewAI crew with governance.
|
|
38
|
+
|
|
39
|
+
Intercepts:
|
|
40
|
+
- kickoff() / kickoff_async()
|
|
41
|
+
- Individual agent executions
|
|
42
|
+
- Task completions
|
|
43
|
+
"""
|
|
44
|
+
crew_id = getattr(crew, 'id', None) or f"crew-{id(crew)}"
|
|
45
|
+
ctx = self.create_context(crew_id)
|
|
46
|
+
|
|
47
|
+
self._wrapped_crews[id(crew)] = crew
|
|
48
|
+
|
|
49
|
+
original = crew
|
|
50
|
+
kernel = self
|
|
51
|
+
|
|
52
|
+
class GovernedCrewAICrew:
|
|
53
|
+
"""CrewAI crew wrapped with Agent OS governance"""
|
|
54
|
+
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self._original = original
|
|
57
|
+
self._ctx = ctx
|
|
58
|
+
self._kernel = kernel
|
|
59
|
+
|
|
60
|
+
def kickoff(self, inputs: dict = None) -> Any:
|
|
61
|
+
"""Governed kickoff"""
|
|
62
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, inputs)
|
|
63
|
+
if not allowed:
|
|
64
|
+
from .langchain_adapter import PolicyViolationError
|
|
65
|
+
raise PolicyViolationError(reason)
|
|
66
|
+
|
|
67
|
+
# Wrap individual agents if possible
|
|
68
|
+
if hasattr(self._original, 'agents'):
|
|
69
|
+
for agent in self._original.agents:
|
|
70
|
+
self._wrap_agent(agent)
|
|
71
|
+
|
|
72
|
+
result = self._original.kickoff(inputs)
|
|
73
|
+
|
|
74
|
+
valid, reason = self._kernel.post_execute(self._ctx, result)
|
|
75
|
+
if not valid:
|
|
76
|
+
from .langchain_adapter import PolicyViolationError
|
|
77
|
+
raise PolicyViolationError(reason)
|
|
78
|
+
|
|
79
|
+
return result
|
|
80
|
+
|
|
81
|
+
async def kickoff_async(self, inputs: dict = None) -> Any:
|
|
82
|
+
"""Governed async kickoff"""
|
|
83
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, inputs)
|
|
84
|
+
if not allowed:
|
|
85
|
+
from .langchain_adapter import PolicyViolationError
|
|
86
|
+
raise PolicyViolationError(reason)
|
|
87
|
+
|
|
88
|
+
result = await self._original.kickoff_async(inputs)
|
|
89
|
+
|
|
90
|
+
valid, reason = self._kernel.post_execute(self._ctx, result)
|
|
91
|
+
if not valid:
|
|
92
|
+
from .langchain_adapter import PolicyViolationError
|
|
93
|
+
raise PolicyViolationError(reason)
|
|
94
|
+
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
def _wrap_agent(self, agent):
|
|
98
|
+
"""Add governance hooks to individual agent"""
|
|
99
|
+
original_execute = getattr(agent, 'execute_task', None)
|
|
100
|
+
if original_execute:
|
|
101
|
+
def governed_execute(task, *args, **kwargs):
|
|
102
|
+
self._kernel.pre_execute(self._ctx, task)
|
|
103
|
+
result = original_execute(task, *args, **kwargs)
|
|
104
|
+
self._kernel.post_execute(self._ctx, result)
|
|
105
|
+
return result
|
|
106
|
+
agent.execute_task = governed_execute
|
|
107
|
+
|
|
108
|
+
def __getattr__(self, name):
|
|
109
|
+
return getattr(self._original, name)
|
|
110
|
+
|
|
111
|
+
return GovernedCrewAICrew()
|
|
112
|
+
|
|
113
|
+
def unwrap(self, governed_crew: Any) -> Any:
|
|
114
|
+
"""Get original crew from wrapped version"""
|
|
115
|
+
return governed_crew._original
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# Convenience function
|
|
119
|
+
def wrap(crew: Any, policy: Optional[GovernancePolicy] = None) -> Any:
|
|
120
|
+
"""Quick wrapper for CrewAI crews"""
|
|
121
|
+
return CrewAIKernel(policy).wrap(crew)
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LangChain Integration
|
|
3
|
+
|
|
4
|
+
Wraps LangChain agents/chains with Agent OS governance.
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
from agent_os.integrations import LangChainKernel
|
|
8
|
+
|
|
9
|
+
kernel = LangChainKernel()
|
|
10
|
+
governed_chain = kernel.wrap(my_langchain_chain)
|
|
11
|
+
|
|
12
|
+
# Now all invocations go through Agent OS
|
|
13
|
+
result = governed_chain.invoke({"input": "..."})
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from typing import Any, Optional
|
|
17
|
+
from functools import wraps
|
|
18
|
+
|
|
19
|
+
from .base import BaseIntegration, GovernancePolicy, ExecutionContext
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LangChainKernel(BaseIntegration):
|
|
23
|
+
"""
|
|
24
|
+
LangChain adapter for Agent OS.
|
|
25
|
+
|
|
26
|
+
Supports:
|
|
27
|
+
- Chains (invoke, ainvoke)
|
|
28
|
+
- Agents (run, arun)
|
|
29
|
+
- Runnables (invoke, batch, stream)
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, policy: Optional[GovernancePolicy] = None):
|
|
33
|
+
super().__init__(policy)
|
|
34
|
+
self._wrapped_agents: dict[int, Any] = {} # id(wrapped) -> original
|
|
35
|
+
|
|
36
|
+
def wrap(self, agent: Any) -> Any:
|
|
37
|
+
"""
|
|
38
|
+
Wrap a LangChain agent/chain with governance.
|
|
39
|
+
|
|
40
|
+
Intercepts:
|
|
41
|
+
- invoke() / ainvoke()
|
|
42
|
+
- run() / arun()
|
|
43
|
+
- batch() / abatch()
|
|
44
|
+
- stream() / astream()
|
|
45
|
+
"""
|
|
46
|
+
# Get agent ID from the object
|
|
47
|
+
agent_id = getattr(agent, 'name', None) or f"langchain-{id(agent)}"
|
|
48
|
+
ctx = self.create_context(agent_id)
|
|
49
|
+
|
|
50
|
+
# Store original
|
|
51
|
+
self._wrapped_agents[id(agent)] = agent
|
|
52
|
+
|
|
53
|
+
# Create wrapper class
|
|
54
|
+
original = agent
|
|
55
|
+
kernel = self
|
|
56
|
+
|
|
57
|
+
class GovernedLangChainAgent:
|
|
58
|
+
"""LangChain agent wrapped with Agent OS governance"""
|
|
59
|
+
|
|
60
|
+
def __init__(self):
|
|
61
|
+
self._original = original
|
|
62
|
+
self._ctx = ctx
|
|
63
|
+
self._kernel = kernel
|
|
64
|
+
|
|
65
|
+
def invoke(self, input_data: Any, **kwargs) -> Any:
|
|
66
|
+
"""Governed invoke"""
|
|
67
|
+
# Pre-check
|
|
68
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, input_data)
|
|
69
|
+
if not allowed:
|
|
70
|
+
raise PolicyViolationError(reason)
|
|
71
|
+
|
|
72
|
+
# Execute
|
|
73
|
+
result = self._original.invoke(input_data, **kwargs)
|
|
74
|
+
|
|
75
|
+
# Post-check
|
|
76
|
+
valid, reason = self._kernel.post_execute(self._ctx, result)
|
|
77
|
+
if not valid:
|
|
78
|
+
raise PolicyViolationError(reason)
|
|
79
|
+
|
|
80
|
+
return result
|
|
81
|
+
|
|
82
|
+
async def ainvoke(self, input_data: Any, **kwargs) -> Any:
|
|
83
|
+
"""Governed async invoke"""
|
|
84
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, input_data)
|
|
85
|
+
if not allowed:
|
|
86
|
+
raise PolicyViolationError(reason)
|
|
87
|
+
|
|
88
|
+
result = await self._original.ainvoke(input_data, **kwargs)
|
|
89
|
+
|
|
90
|
+
valid, reason = self._kernel.post_execute(self._ctx, result)
|
|
91
|
+
if not valid:
|
|
92
|
+
raise PolicyViolationError(reason)
|
|
93
|
+
|
|
94
|
+
return result
|
|
95
|
+
|
|
96
|
+
def run(self, *args, **kwargs) -> Any:
|
|
97
|
+
"""Governed run (for agents)"""
|
|
98
|
+
input_data = args[0] if args else kwargs
|
|
99
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, input_data)
|
|
100
|
+
if not allowed:
|
|
101
|
+
raise PolicyViolationError(reason)
|
|
102
|
+
|
|
103
|
+
result = self._original.run(*args, **kwargs)
|
|
104
|
+
|
|
105
|
+
valid, reason = self._kernel.post_execute(self._ctx, result)
|
|
106
|
+
if not valid:
|
|
107
|
+
raise PolicyViolationError(reason)
|
|
108
|
+
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
def batch(self, inputs: list, **kwargs) -> list:
|
|
112
|
+
"""Governed batch"""
|
|
113
|
+
for inp in inputs:
|
|
114
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, inp)
|
|
115
|
+
if not allowed:
|
|
116
|
+
raise PolicyViolationError(reason)
|
|
117
|
+
|
|
118
|
+
results = self._original.batch(inputs, **kwargs)
|
|
119
|
+
|
|
120
|
+
for result in results:
|
|
121
|
+
valid, reason = self._kernel.post_execute(self._ctx, result)
|
|
122
|
+
if not valid:
|
|
123
|
+
raise PolicyViolationError(reason)
|
|
124
|
+
|
|
125
|
+
return results
|
|
126
|
+
|
|
127
|
+
def stream(self, input_data: Any, **kwargs):
|
|
128
|
+
"""Governed stream"""
|
|
129
|
+
allowed, reason = self._kernel.pre_execute(self._ctx, input_data)
|
|
130
|
+
if not allowed:
|
|
131
|
+
raise PolicyViolationError(reason)
|
|
132
|
+
|
|
133
|
+
for chunk in self._original.stream(input_data, **kwargs):
|
|
134
|
+
yield chunk
|
|
135
|
+
|
|
136
|
+
self._kernel.post_execute(self._ctx, None)
|
|
137
|
+
|
|
138
|
+
# Passthrough for non-execution methods
|
|
139
|
+
def __getattr__(self, name):
|
|
140
|
+
return getattr(self._original, name)
|
|
141
|
+
|
|
142
|
+
return GovernedLangChainAgent()
|
|
143
|
+
|
|
144
|
+
def unwrap(self, governed_agent: Any) -> Any:
|
|
145
|
+
"""Get original agent from wrapped version"""
|
|
146
|
+
return governed_agent._original
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
class PolicyViolationError(Exception):
|
|
150
|
+
"""Raised when an agent violates governance policy"""
|
|
151
|
+
pass
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# Convenience function
|
|
155
|
+
def wrap(agent: Any, policy: Optional[GovernancePolicy] = None) -> Any:
|
|
156
|
+
"""Quick wrapper for LangChain agents"""
|
|
157
|
+
return LangChainKernel(policy).wrap(agent)
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-os-kernel
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: A Safety-First Kernel for Autonomous AI Agents - POSIX-inspired primitives with 0% policy violation guarantee
|
|
5
|
+
Project-URL: Homepage, https://github.com/imran-siddique/agent-os
|
|
6
|
+
Project-URL: Documentation, https://github.com/imran-siddique/agent-os/tree/master/docs
|
|
7
|
+
Project-URL: Repository, https://github.com/imran-siddique/agent-os
|
|
8
|
+
Project-URL: Bug Tracker, https://github.com/imran-siddique/agent-os/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/imran-siddique/agent-os/blob/master/CHANGELOG.md
|
|
10
|
+
Author-email: Imran Siddique <imran.siddique@microsoft.com>
|
|
11
|
+
Maintainer-email: Imran Siddique <imran.siddique@microsoft.com>
|
|
12
|
+
License-Expression: MIT
|
|
13
|
+
License-File: LICENSE
|
|
14
|
+
Keywords: agents,ai,autonomous,control-plane,governance,kernel,llm,multi-agent,posix,safety,signals,vfs
|
|
15
|
+
Classifier: Development Status :: 4 - Beta
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Classifier: Topic :: Security
|
|
26
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
27
|
+
Classifier: Topic :: System :: Operating System Kernels
|
|
28
|
+
Classifier: Typing :: Typed
|
|
29
|
+
Requires-Python: >=3.9
|
|
30
|
+
Requires-Dist: pydantic>=2.0.0
|
|
31
|
+
Provides-Extra: all
|
|
32
|
+
Requires-Dist: agent-os[dev,docs,full]; extra == 'all'
|
|
33
|
+
Provides-Extra: amb
|
|
34
|
+
Requires-Dist: aiofiles>=23.0.0; extra == 'amb'
|
|
35
|
+
Requires-Dist: anyio>=3.0.0; extra == 'amb'
|
|
36
|
+
Provides-Extra: atr
|
|
37
|
+
Requires-Dist: docker>=6.0.0; extra == 'atr'
|
|
38
|
+
Provides-Extra: caas
|
|
39
|
+
Requires-Dist: fastapi>=0.100.0; extra == 'caas'
|
|
40
|
+
Requires-Dist: numpy>=1.20.0; extra == 'caas'
|
|
41
|
+
Requires-Dist: pypdf2>=3.0.0; extra == 'caas'
|
|
42
|
+
Requires-Dist: scikit-learn>=1.0.0; extra == 'caas'
|
|
43
|
+
Requires-Dist: uvicorn>=0.20.0; extra == 'caas'
|
|
44
|
+
Provides-Extra: cmvk
|
|
45
|
+
Requires-Dist: numpy>=1.20.0; extra == 'cmvk'
|
|
46
|
+
Provides-Extra: control-plane
|
|
47
|
+
Provides-Extra: core
|
|
48
|
+
Requires-Dist: agent-os[cmvk,control-plane,primitives]; extra == 'core'
|
|
49
|
+
Provides-Extra: dev
|
|
50
|
+
Requires-Dist: black>=23.0.0; extra == 'dev'
|
|
51
|
+
Requires-Dist: mypy>=1.0.0; extra == 'dev'
|
|
52
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
53
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
54
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
55
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
56
|
+
Provides-Extra: docs
|
|
57
|
+
Requires-Dist: mkdocs-material>=9.0.0; extra == 'docs'
|
|
58
|
+
Requires-Dist: mkdocs>=1.5.0; extra == 'docs'
|
|
59
|
+
Requires-Dist: mkdocstrings[python]>=0.24.0; extra == 'docs'
|
|
60
|
+
Provides-Extra: emk
|
|
61
|
+
Requires-Dist: chromadb>=0.4.0; extra == 'emk'
|
|
62
|
+
Requires-Dist: numpy>=1.20.0; extra == 'emk'
|
|
63
|
+
Provides-Extra: full
|
|
64
|
+
Requires-Dist: agent-os[amb,atr,caas,cmvk,control-plane,emk,iatp,mute-agent,primitives,scak]; extra == 'full'
|
|
65
|
+
Provides-Extra: iatp
|
|
66
|
+
Requires-Dist: fastapi>=0.100.0; extra == 'iatp'
|
|
67
|
+
Requires-Dist: httpx>=0.24.0; extra == 'iatp'
|
|
68
|
+
Requires-Dist: uvicorn>=0.20.0; extra == 'iatp'
|
|
69
|
+
Provides-Extra: infrastructure
|
|
70
|
+
Requires-Dist: agent-os[amb,atr,iatp]; extra == 'infrastructure'
|
|
71
|
+
Provides-Extra: intelligence
|
|
72
|
+
Requires-Dist: agent-os[mute-agent,scak]; extra == 'intelligence'
|
|
73
|
+
Provides-Extra: mute-agent
|
|
74
|
+
Provides-Extra: primitives
|
|
75
|
+
Provides-Extra: scak
|
|
76
|
+
Requires-Dist: pyyaml>=6.0; extra == 'scak'
|
|
77
|
+
Description-Content-Type: text/markdown
|
|
78
|
+
|
|
79
|
+
<div align="center">
|
|
80
|
+
|
|
81
|
+
# Agent OS
|
|
82
|
+
|
|
83
|
+
### The Linux Kernel for AI Agents
|
|
84
|
+
|
|
85
|
+
**0% Safety Violations • Deterministic Enforcement • POSIX-Inspired**
|
|
86
|
+
|
|
87
|
+
[](https://pypi.org/project/agent-os/)
|
|
88
|
+
[](LICENSE)
|
|
89
|
+
[](https://python.org)
|
|
90
|
+
|
|
91
|
+
[Quick Start](#-quick-start) • [Why Agent OS?](#-why-agent-os) • [Demos](#-live-demos) • [Integrations](#-integrations) • [Contributing](#-contributing)
|
|
92
|
+
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## 🎯 What is Agent OS?
|
|
98
|
+
|
|
99
|
+
**Agent OS treats LLMs like raw compute and provides OS-level governance.**
|
|
100
|
+
|
|
101
|
+
Current AI agent frameworks let the LLM "decide" everything - including whether to follow safety rules. Agent OS inverts this: the **kernel decides**, the LLM just computes.
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
┌─────────────────────────────────────────────────────────┐
|
|
105
|
+
│ USER SPACE (Untrusted LLM) │
|
|
106
|
+
│ Your agent code runs here. It can crash, hallucinate, │
|
|
107
|
+
│ or misbehave - the kernel survives. │
|
|
108
|
+
├─────────────────────────────────────────────────────────┤
|
|
109
|
+
│ KERNEL SPACE (Trusted) │
|
|
110
|
+
│ Policy Engine │ Flight Recorder │ Signal Dispatch │
|
|
111
|
+
│ If agent violates policy → SIGKILL (non-catchable) │
|
|
112
|
+
└─────────────────────────────────────────────────────────┘
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## ❓ Why Agent OS?
|
|
116
|
+
|
|
117
|
+
### The Problem with Current Approaches
|
|
118
|
+
|
|
119
|
+
| Approach | How it works | Why it fails |
|
|
120
|
+
|----------|--------------|--------------|
|
|
121
|
+
| **Prompt-based safety** | "Please don't do bad things" | LLM can ignore prompts |
|
|
122
|
+
| **Constitutional AI** | Train model to be safe | Training doesn't guarantee |
|
|
123
|
+
| **Guardrails** | Check output after generation | Too late - damage done |
|
|
124
|
+
| **Agent OS** | **Kernel-level enforcement** | **Can't bypass the kernel** |
|
|
125
|
+
|
|
126
|
+
### Real Benchmark Results
|
|
127
|
+
|
|
128
|
+
| Metric | Prompt-based | Agent OS |
|
|
129
|
+
|--------|-------------|----------|
|
|
130
|
+
| Safety Violations | 26.67% | **0.00%** |
|
|
131
|
+
| Response Tokens | 26.1 avg | **0.5 avg** |
|
|
132
|
+
| Deterministic | No | **Yes** |
|
|
133
|
+
|
|
134
|
+
## 🚀 Quick Start
|
|
135
|
+
|
|
136
|
+
### Option 1: pip install (30 seconds)
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
pip install agent-os
|
|
140
|
+
|
|
141
|
+
# Verify installation
|
|
142
|
+
python -c "from agent_os import KernelSpace; print('Agent OS ready!')"
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Option 2: GitHub CLI Extension (Recommended for daily use)
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
# Install the gh extension
|
|
149
|
+
gh extension install imran-siddique/gh-agent-os
|
|
150
|
+
|
|
151
|
+
# Now use Agent OS directly from your terminal
|
|
152
|
+
gh agent-os run "analyze this codebase for security issues"
|
|
153
|
+
gh agent-os audit --policy pci-dss
|
|
154
|
+
gh agent-os status
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Option 3: Docker (Production)
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
docker pull ghcr.io/imran-siddique/agent-os:latest
|
|
161
|
+
docker run -it agent-os agentctl --help
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## 💡 Core Concepts (5 minutes)
|
|
165
|
+
|
|
166
|
+
### 1. Signals - Control Your Agents Like Processes
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
from agent_os import AgentSignal, SignalDispatcher
|
|
170
|
+
|
|
171
|
+
# Pause agent to inspect state (like Ctrl+Z)
|
|
172
|
+
dispatcher.signal(agent_id, AgentSignal.SIGSTOP)
|
|
173
|
+
|
|
174
|
+
# Resume execution
|
|
175
|
+
dispatcher.signal(agent_id, AgentSignal.SIGCONT)
|
|
176
|
+
|
|
177
|
+
# Policy violation? Kernel kills it (non-catchable)
|
|
178
|
+
dispatcher.signal(agent_id, AgentSignal.SIGKILL)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 2. Virtual File System - Memory That Makes Sense
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from agent_os import AgentVFS
|
|
185
|
+
|
|
186
|
+
vfs = AgentVFS(agent_id="agent-001")
|
|
187
|
+
|
|
188
|
+
# Standard mount points (like /home, /tmp, /etc)
|
|
189
|
+
vfs.write("/mem/working/task.txt", "Current task...") # Ephemeral
|
|
190
|
+
vfs.write("/mem/episodic/session.log", "What happened") # Experience
|
|
191
|
+
vfs.read("/policy/allowed_actions.yaml") # Read-only rules
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 3. IPC Pipes - Agents Talk Through Policies
|
|
195
|
+
|
|
196
|
+
```python
|
|
197
|
+
from agent_os.iatp import Pipeline, PolicyCheckPipe
|
|
198
|
+
|
|
199
|
+
# Unix-style piping: agent1 | policy | agent2
|
|
200
|
+
pipeline = Pipeline([
|
|
201
|
+
research_agent,
|
|
202
|
+
PolicyCheckPipe(allowed=["ResearchResult"]), # Type check!
|
|
203
|
+
summary_agent
|
|
204
|
+
])
|
|
205
|
+
|
|
206
|
+
# If research_agent outputs wrong type → pipeline fails safely
|
|
207
|
+
result = await pipeline.execute("Find recent AI papers")
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## 🎬 Live Demos
|
|
211
|
+
|
|
212
|
+
Four production-ready demos showing Agent OS in action:
|
|
213
|
+
|
|
214
|
+
| Demo | Industry | What it shows | Run it |
|
|
215
|
+
|------|----------|---------------|--------|
|
|
216
|
+
| **[Carbon Auditor](examples/carbon-auditor/)** | Climate | CMVK drift detection catches $5M fraud | `python examples/carbon-auditor/demo.py` |
|
|
217
|
+
| **[Grid Balancing](examples/grid-balancing/)** | Energy | 100 agents negotiate in 100ms | `python examples/grid-balancing/demo.py` |
|
|
218
|
+
| **[DeFi Sentinel](examples/defi-sentinel/)** | Crypto | Stop hacks in 142ms | `python examples/defi-sentinel/demo.py` |
|
|
219
|
+
| **[Pharma Compliance](examples/pharma-compliance/)** | Healthcare | Find contradictions in 100K pages | `python examples/pharma-compliance/demo.py` |
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# Run all demos
|
|
223
|
+
cd examples && docker-compose up
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## 🔌 Integrations
|
|
227
|
+
|
|
228
|
+
### Works With Your Existing Stack
|
|
229
|
+
|
|
230
|
+
Agent OS doesn't replace your tools - it governs them:
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
# With LangChain
|
|
234
|
+
from agent_os.integrations import langchain_kernel
|
|
235
|
+
chain = langchain_kernel.wrap(your_langchain_agent)
|
|
236
|
+
|
|
237
|
+
# With CrewAI
|
|
238
|
+
from agent_os.integrations import crewai_kernel
|
|
239
|
+
crew = crewai_kernel.wrap(your_crew)
|
|
240
|
+
|
|
241
|
+
# With AutoGen
|
|
242
|
+
from agent_os.integrations import autogen_kernel
|
|
243
|
+
autogen_kernel.govern(your_autogen_agents)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### GitHub Integration
|
|
247
|
+
|
|
248
|
+
```yaml
|
|
249
|
+
# .github/workflows/agent-os.yml
|
|
250
|
+
name: Agent OS Safety Check
|
|
251
|
+
on: [push, pull_request]
|
|
252
|
+
|
|
253
|
+
jobs:
|
|
254
|
+
safety-audit:
|
|
255
|
+
runs-on: ubuntu-latest
|
|
256
|
+
steps:
|
|
257
|
+
- uses: actions/checkout@v4
|
|
258
|
+
- uses: imran-siddique/agent-os-action@v1
|
|
259
|
+
with:
|
|
260
|
+
policy: .agent-os/policy.yaml
|
|
261
|
+
fail-on-violation: true
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### VS Code Extension
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
# Install from marketplace
|
|
268
|
+
code --install-extension imran-siddique.agent-os
|
|
269
|
+
|
|
270
|
+
# Or use Command Palette: "Agent OS: Audit Current File"
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### CLI for Daily Workflows
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# Audit any agent codebase
|
|
277
|
+
agentctl audit ./my-agent-project
|
|
278
|
+
|
|
279
|
+
# Run with safety constraints
|
|
280
|
+
agentctl run --policy strict "agent.py"
|
|
281
|
+
|
|
282
|
+
# Monitor running agents
|
|
283
|
+
agentctl status --watch
|
|
284
|
+
|
|
285
|
+
# Replay agent execution from flight recorder
|
|
286
|
+
agentctl replay --from checkpoint-001
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## 📦 Package Architecture
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
agent-os/
|
|
293
|
+
├── L1: Primitives (Foundation)
|
|
294
|
+
│ ├── primitives # Failure types, base models
|
|
295
|
+
│ ├── cmvk # Cross-model verification
|
|
296
|
+
│ ├── caas # Context-as-a-Service
|
|
297
|
+
│ └── emk # Episodic Memory Kernel
|
|
298
|
+
│
|
|
299
|
+
├── L2: Infrastructure (Communication)
|
|
300
|
+
│ ├── iatp # Inter-Agent Trust Protocol
|
|
301
|
+
│ ├── amb # Agent Message Bus
|
|
302
|
+
│ └── atr # Agent Tool Registry
|
|
303
|
+
│
|
|
304
|
+
├── L3: Framework (Governance)
|
|
305
|
+
│ └── control-plane # Kernel, signals, VFS
|
|
306
|
+
│
|
|
307
|
+
└── L4: Intelligence (Self-Correction)
|
|
308
|
+
├── scak # Self-Correcting Agent Kernel
|
|
309
|
+
└── mute-agent # Reasoning/Execution split
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Install what you need:
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
pip install agent-os # Core only
|
|
316
|
+
pip install agent-os[control-plane] # + Governance
|
|
317
|
+
pip install agent-os[full] # Everything
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## 🆚 How We Compare
|
|
321
|
+
|
|
322
|
+
| Feature | LangChain | AutoGen | CrewAI | AIOS | **Agent OS** |
|
|
323
|
+
|---------|-----------|---------|--------|------|--------------|
|
|
324
|
+
| Multi-agent | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
325
|
+
| Safety guarantees | ❌ | ❌ | ❌ | ❌ | **✅ Kernel-level** |
|
|
326
|
+
| Deterministic | ❌ | ❌ | ❌ | ❌ | **✅** |
|
|
327
|
+
| Process isolation | ❌ | ❌ | ❌ | ❌ | **✅ Kernel/User** |
|
|
328
|
+
| Policy enforcement | ❌ | ❌ | ❌ | ❌ | **✅ SIGKILL** |
|
|
329
|
+
| Audit trail | Partial | Partial | Partial | ❌ | **✅ Flight Recorder** |
|
|
330
|
+
| Memory model | Ad-hoc | Ad-hoc | Ad-hoc | Short/Long | **✅ VFS** |
|
|
331
|
+
|
|
332
|
+
**TL;DR**: Other frameworks help you *build* agents. Agent OS helps you *trust* them.
|
|
333
|
+
|
|
334
|
+
## 🤝 Contributing
|
|
335
|
+
|
|
336
|
+
We welcome contributions! Agent OS is designed to be extended.
|
|
337
|
+
|
|
338
|
+
### Good First Issues
|
|
339
|
+
|
|
340
|
+
- 🏷️ [`good-first-issue`](https://github.com/imran-siddique/agent-os/labels/good-first-issue) - Perfect for newcomers
|
|
341
|
+
- 📚 [`documentation`](https://github.com/imran-siddique/agent-os/labels/documentation) - Help improve docs
|
|
342
|
+
- 🧪 [`needs-tests`](https://github.com/imran-siddique/agent-os/labels/needs-tests) - Add test coverage
|
|
343
|
+
|
|
344
|
+
### Development Setup
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
# Clone and setup
|
|
348
|
+
git clone https://github.com/imran-siddique/agent-os.git
|
|
349
|
+
cd agent-os
|
|
350
|
+
pip install -e ".[dev]"
|
|
351
|
+
|
|
352
|
+
# Run tests
|
|
353
|
+
pytest
|
|
354
|
+
|
|
355
|
+
# Run a specific demo
|
|
356
|
+
python examples/carbon-auditor/demo.py
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
### Integration Bounties
|
|
360
|
+
|
|
361
|
+
Want to add an integration? We're looking for:
|
|
362
|
+
|
|
363
|
+
| Integration | Bounty | Status |
|
|
364
|
+
|-------------|--------|--------|
|
|
365
|
+
| LangChain adapter | 🎁 | Open |
|
|
366
|
+
| CrewAI adapter | 🎁 | Open |
|
|
367
|
+
| AutoGen adapter | 🎁 | Open |
|
|
368
|
+
| OpenAI Swarm adapter | 🎁 | Open |
|
|
369
|
+
| Anthropic Claude adapter | 🎁 | Open |
|
|
370
|
+
|
|
371
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for full guidelines.
|
|
372
|
+
|
|
373
|
+
## 📖 Documentation
|
|
374
|
+
|
|
375
|
+
- **[Architecture Guide](docs/architecture.md)** - Deep dive into kernel design
|
|
376
|
+
- **[API Reference](docs/api/)** - Full API documentation
|
|
377
|
+
- **[Examples](examples/)** - Working demos
|
|
378
|
+
- **[AIOS Comparison](docs/AIOS_COMPARISON.md)** - Detailed competitor analysis
|
|
379
|
+
|
|
380
|
+
## 🔬 Research
|
|
381
|
+
|
|
382
|
+
Agent OS is designed for both production and academic use:
|
|
383
|
+
|
|
384
|
+
- **Target**: ASPLOS 2026 Workshop on Agentic Systems
|
|
385
|
+
- **Paper**: "Agent OS: A Safety-First Kernel for Autonomous AI Agents"
|
|
386
|
+
- **Novel Contribution**: First OS-level governance for LLM agents
|
|
387
|
+
|
|
388
|
+
## 📜 License
|
|
389
|
+
|
|
390
|
+
MIT License - Use it, modify it, ship it. See [LICENSE](LICENSE).
|
|
391
|
+
|
|
392
|
+
---
|
|
393
|
+
|
|
394
|
+
<div align="center">
|
|
395
|
+
|
|
396
|
+
**Built for engineers who don't trust their agents (yet).**
|
|
397
|
+
|
|
398
|
+
[⭐ Star us on GitHub](https://github.com/imran-siddique/agent-os) • [📦 PyPI](https://pypi.org/project/agent-os/) • [💬 Discussions](https://github.com/imran-siddique/agent-os/discussions)
|
|
399
|
+
|
|
400
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
agent_os/__init__.py,sha256=3GVytq4q7NrLk1-lB3E5d_IuuufGTH5_NL5dcjXkXOA,8085
|
|
2
|
+
agent_os/cli.py,sha256=UUbxQPCptpCnO9m3uPaRQESYzdSMwkRB-PWTDHctCpE,1186
|
|
3
|
+
agent_os/integrations/__init__.py,sha256=jQaIoLNWYXLwoLU0w6WYf8Pi2n988z-a9EGVzCaDt2Y,386
|
|
4
|
+
agent_os/integrations/autogen_adapter.py,sha256=KFyEw4Y_IYgQM6CpaTjCHs9HCX8hPiCzeAz2E__AVrg,4742
|
|
5
|
+
agent_os/integrations/base.py,sha256=0CZOtHC52Eg5wdr5qYI1s40nnSvbXvz8PeJ1LF97Bc0,4356
|
|
6
|
+
agent_os/integrations/crewai_adapter.py,sha256=B0uppXizOuvj9PTd89lxMDoedBzdrt8XlRZXNSfJdbs,4395
|
|
7
|
+
agent_os/integrations/langchain_adapter.py,sha256=SrGFv9m_IfMwklc58_Nv8WRNdcyOIEAYSPcjTRFTLoQ,5636
|
|
8
|
+
agent_os_kernel-1.1.0.dist-info/METADATA,sha256=L6bSJ1UOlirp0io5xlsT9j1W7xps6gZw-eqViaXVH1M,13610
|
|
9
|
+
agent_os_kernel-1.1.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
10
|
+
agent_os_kernel-1.1.0.dist-info/entry_points.txt,sha256=wh7atGeSHUk0eDOU8r94VhahDenzOcyp7O9uBygjXl0,76
|
|
11
|
+
agent_os_kernel-1.1.0.dist-info/licenses/LICENSE,sha256=6rUhFLV_7Agj5qal2I4M8h66QadoY6xf51VOz8m7BrQ,1097
|
|
12
|
+
agent_os_kernel-1.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Imran Siddique
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|