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,697 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Agent Virtual File System (VFS) - POSIX-style memory abstraction for agents.
5
+
6
+ This module provides a virtual file system interface for agent memory,
7
+ inspired by POSIX VFS but designed for AI agent state management.
8
+
9
+ Instead of high-level "Semantic Memory" or "Vector Store" abstractions,
10
+ this provides a standard POSIX-like interface that can mount ANY backend.
11
+
12
+ Mount Points:
13
+ /mem/working - Working memory (current context, scratchpad)
14
+ /mem/episodic - Episodic memory (past interactions, experiences)
15
+ /mem/semantic - Semantic memory (facts, knowledge)
16
+ /mem/procedural - Procedural memory (learned skills, patterns)
17
+ /state - Agent state (checkpoints, snapshots)
18
+ /tools - Tool interfaces (mounted dynamically)
19
+ /policy - Policy files (read-only from user-space)
20
+
21
+ Design Philosophy:
22
+ - Everything is a file (UNIX philosophy)
23
+ - Backends are drivers (Pinecone, Weaviate, Redis = mount points)
24
+ - Kernel controls mount permissions
25
+ - User-space agents see unified interface
26
+ """
27
+
28
+ from abc import ABC, abstractmethod
29
+ from dataclasses import dataclass, field
30
+ from datetime import datetime, timezone
31
+ from enum import IntFlag, auto
32
+ from pathlib import PurePosixPath
33
+ from typing import (
34
+ Any, Dict, List, Optional, Union, Iterator, BinaryIO, TextIO, Callable
35
+ )
36
+ import io
37
+ import json
38
+ import logging
39
+ import hashlib
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+
44
+ class FileMode(IntFlag):
45
+ """File permission modes (POSIX-style)."""
46
+ NONE = 0
47
+ READ = auto() # r
48
+ WRITE = auto() # w
49
+ EXECUTE = auto() # x (for tools/procedures)
50
+ APPEND = auto() # a
51
+
52
+ # Common combinations
53
+ RO = READ
54
+ RW = READ | WRITE
55
+ RWX = READ | WRITE | EXECUTE
56
+
57
+
58
+ class FileType(IntFlag):
59
+ """File types in the VFS."""
60
+ REGULAR = auto() # Regular data file
61
+ DIRECTORY = auto() # Directory
62
+ SYMLINK = auto() # Symbolic link
63
+ DEVICE = auto() # Device file (backend connection)
64
+ SOCKET = auto() # IPC socket
65
+ FIFO = auto() # Named pipe
66
+
67
+
68
+ @dataclass
69
+ class INode:
70
+ """
71
+ Index node - metadata for a VFS entry.
72
+
73
+ Inspired by UNIX inodes but adapted for agent memory.
74
+ """
75
+ path: str
76
+ file_type: FileType
77
+ mode: FileMode
78
+ size: int = 0
79
+ created: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
80
+ modified: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
81
+ accessed: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
82
+ owner: str = "agent"
83
+ group: str = "agents"
84
+
85
+ # Extended attributes (agent-specific)
86
+ embedding_dim: Optional[int] = None # For vector entries
87
+ content_hash: Optional[str] = None
88
+ ttl_seconds: Optional[int] = None # Time-to-live
89
+ tags: List[str] = field(default_factory=list)
90
+ metadata: Dict[str, Any] = field(default_factory=dict)
91
+
92
+ def to_dict(self) -> Dict[str, Any]:
93
+ return {
94
+ "path": self.path,
95
+ "type": self.file_type.name,
96
+ "mode": self.mode.value,
97
+ "size": self.size,
98
+ "created": self.created.isoformat(),
99
+ "modified": self.modified.isoformat(),
100
+ "owner": self.owner,
101
+ "metadata": self.metadata,
102
+ }
103
+
104
+
105
+ @dataclass
106
+ class FileDescriptor:
107
+ """Open file descriptor."""
108
+ fd: int
109
+ path: str
110
+ mode: FileMode
111
+ position: int = 0
112
+ inode: Optional[INode] = None
113
+
114
+
115
+ class VFSBackend(ABC):
116
+ """
117
+ Abstract backend driver for VFS mount points.
118
+
119
+ Implement this to add support for different storage backends:
120
+ - MemoryBackend: In-memory storage (default)
121
+ - RedisBackend: Redis-based persistent storage
122
+ - VectorBackend: Vector database (Pinecone, Weaviate, etc.)
123
+ - SQLBackend: SQL database storage
124
+ """
125
+
126
+ @abstractmethod
127
+ def read(self, path: str) -> bytes:
128
+ """Read file contents."""
129
+ pass
130
+
131
+ @abstractmethod
132
+ def write(self, path: str, data: bytes, mode: FileMode = FileMode.WRITE) -> int:
133
+ """Write data to file. Returns bytes written."""
134
+ pass
135
+
136
+ @abstractmethod
137
+ def delete(self, path: str) -> bool:
138
+ """Delete a file."""
139
+ pass
140
+
141
+ @abstractmethod
142
+ def exists(self, path: str) -> bool:
143
+ """Check if path exists."""
144
+ pass
145
+
146
+ @abstractmethod
147
+ def list_dir(self, path: str) -> List[str]:
148
+ """List directory contents."""
149
+ pass
150
+
151
+ @abstractmethod
152
+ def stat(self, path: str) -> Optional[INode]:
153
+ """Get file metadata."""
154
+ pass
155
+
156
+ @abstractmethod
157
+ def mkdir(self, path: str) -> bool:
158
+ """Create directory."""
159
+ pass
160
+
161
+
162
+ class MemoryBackend(VFSBackend):
163
+ """
164
+ In-memory VFS backend.
165
+
166
+ Simple implementation for working memory and testing.
167
+ Data is lost on agent restart (ephemeral by design).
168
+ """
169
+
170
+ def __init__(self):
171
+ self._files: Dict[str, bytes] = {}
172
+ self._inodes: Dict[str, INode] = {}
173
+ self._dirs: set = {"/"}
174
+
175
+ def read(self, path: str) -> bytes:
176
+ if path not in self._files:
177
+ raise FileNotFoundError(f"No such file: {path}")
178
+
179
+ # Update access time
180
+ if path in self._inodes:
181
+ self._inodes[path].accessed = datetime.now(timezone.utc)
182
+
183
+ return self._files[path]
184
+
185
+ def write(self, path: str, data: bytes, mode: FileMode = FileMode.WRITE) -> int:
186
+ # Ensure parent directory exists - auto-create if needed
187
+ parent = str(PurePosixPath(path).parent)
188
+ if parent not in self._dirs and parent != path:
189
+ # Auto-create parent directories (like mkdir -p)
190
+ self._mkdir_p(parent)
191
+
192
+ if mode & FileMode.APPEND and path in self._files:
193
+ self._files[path] += data
194
+ else:
195
+ self._files[path] = data
196
+
197
+ # Update or create inode
198
+ now = datetime.now(timezone.utc)
199
+ if path in self._inodes:
200
+ self._inodes[path].modified = now
201
+ self._inodes[path].size = len(self._files[path])
202
+ self._inodes[path].content_hash = hashlib.sha256(self._files[path]).hexdigest()[:16]
203
+ else:
204
+ self._inodes[path] = INode(
205
+ path=path,
206
+ file_type=FileType.REGULAR,
207
+ mode=FileMode.RW,
208
+ size=len(data),
209
+ content_hash=hashlib.sha256(data).hexdigest()[:16],
210
+ )
211
+
212
+ return len(data)
213
+
214
+ def delete(self, path: str) -> bool:
215
+ if path in self._files:
216
+ del self._files[path]
217
+ if path in self._inodes:
218
+ del self._inodes[path]
219
+ return True
220
+ return False
221
+
222
+ def exists(self, path: str) -> bool:
223
+ return path in self._files or path in self._dirs
224
+
225
+ def list_dir(self, path: str) -> List[str]:
226
+ if path not in self._dirs:
227
+ raise NotADirectoryError(f"Not a directory: {path}")
228
+
229
+ # Find all entries under this directory
230
+ prefix = path.rstrip("/") + "/"
231
+ entries = set()
232
+
233
+ for p in list(self._files.keys()) + list(self._dirs):
234
+ if p.startswith(prefix):
235
+ # Get the immediate child
236
+ remainder = p[len(prefix):]
237
+ if remainder:
238
+ child = remainder.split("/")[0]
239
+ entries.add(child)
240
+
241
+ return sorted(entries)
242
+
243
+ def stat(self, path: str) -> Optional[INode]:
244
+ if path in self._inodes:
245
+ return self._inodes[path]
246
+ if path in self._dirs:
247
+ return INode(
248
+ path=path,
249
+ file_type=FileType.DIRECTORY,
250
+ mode=FileMode.RWX,
251
+ )
252
+ return None
253
+
254
+ def mkdir(self, path: str) -> bool:
255
+ if path in self._dirs:
256
+ return False
257
+ self._dirs.add(path)
258
+ return True
259
+
260
+ def _mkdir_p(self, path: str) -> None:
261
+ """Create directory and all parent directories (like mkdir -p)."""
262
+ parts = path.strip("/").split("/")
263
+ current = ""
264
+ for part in parts:
265
+ current = current + "/" + part
266
+ if current not in self._dirs:
267
+ self._dirs.add(current)
268
+
269
+
270
+ @dataclass
271
+ class MountPoint:
272
+ """A mounted filesystem."""
273
+ path: str
274
+ backend: VFSBackend
275
+ mode: FileMode = FileMode.RW
276
+ read_only: bool = False
277
+ description: str = ""
278
+
279
+
280
+ class AgentVFS:
281
+ """
282
+ Agent Virtual File System.
283
+
284
+ Provides a unified POSIX-like interface for agent memory,
285
+ with support for multiple backends mounted at different paths.
286
+
287
+ Example:
288
+ vfs = AgentVFS(agent_id="agent-001")
289
+
290
+ # Mount backends
291
+ vfs.mount("/mem/working", MemoryBackend())
292
+ vfs.mount("/mem/episodic", RedisBackend(host="localhost"))
293
+ vfs.mount("/mem/semantic", VectorBackend(client=pinecone_client))
294
+
295
+ # Use like a filesystem
296
+ vfs.write("/mem/working/scratchpad.txt", b"Current task: ...")
297
+ vfs.write("/mem/episodic/2024-01-26/interaction-001.json", data)
298
+
299
+ # Read back
300
+ data = vfs.read("/mem/working/scratchpad.txt")
301
+ """
302
+
303
+ # Standard mount points for agents
304
+ STANDARD_MOUNTS = {
305
+ "/mem/working": "Working memory (ephemeral context)",
306
+ "/mem/episodic": "Episodic memory (experiences)",
307
+ "/mem/semantic": "Semantic memory (facts)",
308
+ "/mem/procedural": "Procedural memory (skills)",
309
+ "/state": "Agent state (checkpoints)",
310
+ "/tools": "Tool interfaces",
311
+ "/policy": "Policy files (read-only)",
312
+ "/ipc": "Inter-process communication",
313
+ }
314
+
315
+ def __init__(self, agent_id: str):
316
+ self.agent_id = agent_id
317
+ self._mounts: Dict[str, MountPoint] = {}
318
+ self._fd_counter = 0
319
+ self._open_files: Dict[int, FileDescriptor] = {}
320
+
321
+ # Create standard mount points with default memory backend
322
+ self._init_standard_mounts()
323
+
324
+ def _init_standard_mounts(self) -> None:
325
+ """Initialize standard mount points with memory backend."""
326
+ default_backend = MemoryBackend()
327
+
328
+ for path, description in self.STANDARD_MOUNTS.items():
329
+ read_only = path == "/policy" # Policy is read-only from user-space
330
+ self._mounts[path] = MountPoint(
331
+ path=path,
332
+ backend=default_backend,
333
+ mode=FileMode.RO if read_only else FileMode.RW,
334
+ read_only=read_only,
335
+ description=description,
336
+ )
337
+ # Create the directory
338
+ default_backend.mkdir(path)
339
+
340
+ def mount(
341
+ self,
342
+ path: str,
343
+ backend: VFSBackend,
344
+ mode: FileMode = FileMode.RW,
345
+ read_only: bool = False,
346
+ ) -> None:
347
+ """
348
+ Mount a backend at the specified path.
349
+
350
+ Args:
351
+ path: Mount point (e.g., "/mem/semantic")
352
+ backend: VFS backend implementation
353
+ mode: Access mode
354
+ read_only: If True, writes are rejected
355
+ """
356
+ logger.info(f"[VFS] Mounting {backend.__class__.__name__} at {path}")
357
+
358
+ self._mounts[path] = MountPoint(
359
+ path=path,
360
+ backend=backend,
361
+ mode=mode,
362
+ read_only=read_only,
363
+ )
364
+
365
+ # Ensure mount point directory exists
366
+ backend.mkdir(path)
367
+
368
+ def unmount(self, path: str) -> bool:
369
+ """Unmount a filesystem."""
370
+ if path in self._mounts:
371
+ logger.info(f"[VFS] Unmounting {path}")
372
+ del self._mounts[path]
373
+ return True
374
+ return False
375
+
376
+ def _resolve_mount(self, path: str) -> tuple[MountPoint, str]:
377
+ """
378
+ Resolve a path to its mount point and relative path.
379
+
380
+ Returns (mount_point, relative_path)
381
+ """
382
+ # Find the longest matching mount point
383
+ best_match = None
384
+ best_len = 0
385
+
386
+ for mount_path in self._mounts:
387
+ if path.startswith(mount_path) and len(mount_path) > best_len:
388
+ best_match = mount_path
389
+ best_len = len(mount_path)
390
+
391
+ if not best_match:
392
+ raise FileNotFoundError(f"No mount point for path: {path}")
393
+
394
+ mount = self._mounts[best_match]
395
+ return mount, path
396
+
397
+ # ========== File Operations ==========
398
+
399
+ def read(self, path: str) -> bytes:
400
+ """Read file contents."""
401
+ mount, full_path = self._resolve_mount(path)
402
+ return mount.backend.read(full_path)
403
+
404
+ def read_text(self, path: str, encoding: str = "utf-8") -> str:
405
+ """Read file as text."""
406
+ return self.read(path).decode(encoding)
407
+
408
+ def read_json(self, path: str) -> Any:
409
+ """Read and parse JSON file."""
410
+ return json.loads(self.read_text(path))
411
+
412
+ def write(self, path: str, data: Union[bytes, str], mode: FileMode = FileMode.WRITE) -> int:
413
+ """Write data to file."""
414
+ mount, full_path = self._resolve_mount(path)
415
+
416
+ if mount.read_only:
417
+ raise PermissionError(f"Mount point is read-only: {mount.path}")
418
+
419
+ if isinstance(data, str):
420
+ data = data.encode("utf-8")
421
+
422
+ return mount.backend.write(full_path, data, mode)
423
+
424
+ def write_json(self, path: str, data: Any, indent: int = 2) -> int:
425
+ """Write data as JSON."""
426
+ return self.write(path, json.dumps(data, indent=indent, default=str))
427
+
428
+ def append(self, path: str, data: Union[bytes, str]) -> int:
429
+ """Append data to file."""
430
+ return self.write(path, data, FileMode.APPEND)
431
+
432
+ def delete(self, path: str) -> bool:
433
+ """Delete a file."""
434
+ mount, full_path = self._resolve_mount(path)
435
+
436
+ if mount.read_only:
437
+ raise PermissionError(f"Mount point is read-only: {mount.path}")
438
+
439
+ return mount.backend.delete(full_path)
440
+
441
+ def exists(self, path: str) -> bool:
442
+ """Check if path exists."""
443
+ try:
444
+ mount, full_path = self._resolve_mount(path)
445
+ return mount.backend.exists(full_path)
446
+ except FileNotFoundError:
447
+ return False
448
+
449
+ def stat(self, path: str) -> Optional[INode]:
450
+ """Get file metadata."""
451
+ mount, full_path = self._resolve_mount(path)
452
+ return mount.backend.stat(full_path)
453
+
454
+ def ls(self, path: str = "/") -> List[str]:
455
+ """List directory contents."""
456
+ mount, full_path = self._resolve_mount(path)
457
+ return mount.backend.list_dir(full_path)
458
+
459
+ def mkdir(self, path: str) -> bool:
460
+ """Create directory."""
461
+ mount, full_path = self._resolve_mount(path)
462
+
463
+ if mount.read_only:
464
+ raise PermissionError(f"Mount point is read-only: {mount.path}")
465
+
466
+ return mount.backend.mkdir(full_path)
467
+
468
+ # ========== File Descriptor Operations (POSIX-style) ==========
469
+
470
+ def open(self, path: str, mode: FileMode = FileMode.READ) -> int:
471
+ """
472
+ Open a file and return a file descriptor.
473
+
474
+ This provides a more traditional POSIX-style interface.
475
+ """
476
+ mount, full_path = self._resolve_mount(path)
477
+
478
+ if mode & FileMode.WRITE and mount.read_only:
479
+ raise PermissionError(f"Cannot open for writing: {path}")
480
+
481
+ inode = mount.backend.stat(full_path)
482
+
483
+ self._fd_counter += 1
484
+ fd = self._fd_counter
485
+
486
+ self._open_files[fd] = FileDescriptor(
487
+ fd=fd,
488
+ path=full_path,
489
+ mode=mode,
490
+ inode=inode,
491
+ )
492
+
493
+ return fd
494
+
495
+ def close(self, fd: int) -> None:
496
+ """Close a file descriptor."""
497
+ if fd in self._open_files:
498
+ del self._open_files[fd]
499
+
500
+ def fd_read(self, fd: int, size: int = -1) -> bytes:
501
+ """Read from file descriptor."""
502
+ if fd not in self._open_files:
503
+ raise ValueError(f"Invalid file descriptor: {fd}")
504
+
505
+ desc = self._open_files[fd]
506
+ data = self.read(desc.path)
507
+
508
+ if size < 0:
509
+ return data[desc.position:]
510
+
511
+ result = data[desc.position:desc.position + size]
512
+ desc.position += len(result)
513
+ return result
514
+
515
+ def fd_write(self, fd: int, data: bytes) -> int:
516
+ """Write to file descriptor."""
517
+ if fd not in self._open_files:
518
+ raise ValueError(f"Invalid file descriptor: {fd}")
519
+
520
+ desc = self._open_files[fd]
521
+ if not (desc.mode & FileMode.WRITE):
522
+ raise PermissionError("File not opened for writing")
523
+
524
+ return self.write(desc.path, data)
525
+
526
+ # ========== Memory-Specific Operations ==========
527
+
528
+ def save_checkpoint(self, checkpoint_id: str, state: Dict[str, Any]) -> str:
529
+ """Save agent state checkpoint."""
530
+ path = f"/state/checkpoints/{checkpoint_id}.json"
531
+ self.write_json(path, {
532
+ "checkpoint_id": checkpoint_id,
533
+ "timestamp": datetime.now(timezone.utc).isoformat(),
534
+ "agent_id": self.agent_id,
535
+ "state": state,
536
+ })
537
+ logger.info(f"[VFS] Saved checkpoint: {checkpoint_id}")
538
+ return path
539
+
540
+ def load_checkpoint(self, checkpoint_id: str) -> Dict[str, Any]:
541
+ """Load agent state from checkpoint."""
542
+ path = f"/state/checkpoints/{checkpoint_id}.json"
543
+ data = self.read_json(path)
544
+ logger.info(f"[VFS] Loaded checkpoint: {checkpoint_id}")
545
+ return data.get("state", {})
546
+
547
+ def log_episodic(self, event: Dict[str, Any], event_id: Optional[str] = None) -> str:
548
+ """Log an episodic memory event."""
549
+ if not event_id:
550
+ event_id = datetime.now(timezone.utc).strftime("%Y%m%d-%H%M%S-%f")
551
+
552
+ path = f"/mem/episodic/{event_id}.json"
553
+ self.write_json(path, {
554
+ "event_id": event_id,
555
+ "timestamp": datetime.now(timezone.utc).isoformat(),
556
+ "event": event,
557
+ })
558
+ return path
559
+
560
+ def get_working_memory(self) -> Dict[str, Any]:
561
+ """Get all working memory contents."""
562
+ result = {}
563
+ for name in self.ls("/mem/working"):
564
+ path = f"/mem/working/{name}"
565
+ try:
566
+ if name.endswith(".json"):
567
+ result[name] = self.read_json(path)
568
+ else:
569
+ result[name] = self.read_text(path)
570
+ except Exception:
571
+ result[name] = f"<binary: {self.stat(path).size if self.stat(path) else '?'} bytes>"
572
+ return result
573
+
574
+ def clear_working_memory(self) -> int:
575
+ """Clear working memory. Returns number of files deleted."""
576
+ count = 0
577
+ for name in self.ls("/mem/working"):
578
+ if self.delete(f"/mem/working/{name}"):
579
+ count += 1
580
+ return count
581
+
582
+ def get_mount_info(self) -> List[Dict[str, Any]]:
583
+ """Get information about all mount points."""
584
+ return [
585
+ {
586
+ "path": mp.path,
587
+ "backend": mp.backend.__class__.__name__,
588
+ "mode": mp.mode.name,
589
+ "read_only": mp.read_only,
590
+ "description": mp.description or self.STANDARD_MOUNTS.get(mp.path, ""),
591
+ }
592
+ for mp in self._mounts.values()
593
+ ]
594
+
595
+
596
+ # ========== Backend Implementations ==========
597
+
598
+ class VectorBackend(VFSBackend):
599
+ """
600
+ Vector database backend stub.
601
+
602
+ This is a placeholder for vector store integration.
603
+ Implement with actual Pinecone/Weaviate/Qdrant client.
604
+ """
605
+
606
+ def __init__(self, client: Any = None, namespace: str = "default"):
607
+ self.client = client
608
+ self.namespace = namespace
609
+ self._fallback = MemoryBackend() # Fallback for non-vector operations
610
+ logger.info(f"[VectorBackend] Initialized with namespace: {namespace}")
611
+
612
+ def read(self, path: str) -> bytes:
613
+ # For vector stores, reading returns the stored document
614
+ return self._fallback.read(path)
615
+
616
+ def write(self, path: str, data: bytes, mode: FileMode = FileMode.WRITE) -> int:
617
+ # For vector stores, this would upsert to the index
618
+ # Actual implementation would embed and store
619
+ return self._fallback.write(path, data, mode)
620
+
621
+ def delete(self, path: str) -> bool:
622
+ return self._fallback.delete(path)
623
+
624
+ def exists(self, path: str) -> bool:
625
+ return self._fallback.exists(path)
626
+
627
+ def list_dir(self, path: str) -> List[str]:
628
+ return self._fallback.list_dir(path)
629
+
630
+ def stat(self, path: str) -> Optional[INode]:
631
+ return self._fallback.stat(path)
632
+
633
+ def mkdir(self, path: str) -> bool:
634
+ return self._fallback.mkdir(path)
635
+
636
+ # Vector-specific methods
637
+ def search(
638
+ self,
639
+ query_vector: List[float],
640
+ top_k: int = 10,
641
+ filter_dict: Optional[Dict[str, Any]] = None,
642
+ ) -> List[Dict[str, Any]]:
643
+ """
644
+ Search for similar vectors.
645
+
646
+ Override with actual vector search implementation.
647
+ """
648
+ logger.warning("[VectorBackend] search() not implemented - using stub")
649
+ return []
650
+
651
+ def embed_and_store(
652
+ self,
653
+ path: str,
654
+ text: str,
655
+ metadata: Optional[Dict[str, Any]] = None,
656
+ ) -> str:
657
+ """
658
+ Embed text and store in vector database.
659
+
660
+ Override with actual embedding implementation.
661
+ """
662
+ logger.warning("[VectorBackend] embed_and_store() not implemented - using stub")
663
+ return self._fallback.write(path, text.encode("utf-8"))
664
+
665
+
666
+ # ========== Convenience Functions ==========
667
+
668
+ def create_agent_vfs(
669
+ agent_id: str,
670
+ working_backend: Optional[VFSBackend] = None,
671
+ episodic_backend: Optional[VFSBackend] = None,
672
+ semantic_backend: Optional[VFSBackend] = None,
673
+ ) -> AgentVFS:
674
+ """
675
+ Create an AgentVFS with optional custom backends.
676
+
677
+ Args:
678
+ agent_id: Unique agent identifier
679
+ working_backend: Backend for /mem/working (default: MemoryBackend)
680
+ episodic_backend: Backend for /mem/episodic (default: MemoryBackend)
681
+ semantic_backend: Backend for /mem/semantic (default: MemoryBackend)
682
+
683
+ Returns:
684
+ Configured AgentVFS instance
685
+ """
686
+ vfs = AgentVFS(agent_id)
687
+
688
+ if working_backend:
689
+ vfs.mount("/mem/working", working_backend)
690
+
691
+ if episodic_backend:
692
+ vfs.mount("/mem/episodic", episodic_backend)
693
+
694
+ if semantic_backend:
695
+ vfs.mount("/mem/semantic", semantic_backend)
696
+
697
+ return vfs