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,402 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Safe File Reader Tool.
5
+
6
+ Provides read-only file access with security controls:
7
+ - Path sandboxing (only read from allowed directories)
8
+ - No directory traversal (../ blocked)
9
+ - File size limits
10
+ - Extension filtering
11
+ - No symbolic link following outside sandbox
12
+ """
13
+
14
+ import os
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List, Optional, Set
17
+
18
+ from atr.decorator import tool
19
+
20
+
21
+ class FileReaderTool:
22
+ """
23
+ Safe file reader with path sandboxing.
24
+
25
+ Features:
26
+ - Read-only operations only
27
+ - Sandbox path enforcement (can't read outside allowed dirs)
28
+ - Directory traversal prevention
29
+ - File size limits
30
+ - Extension whitelisting
31
+ - Symlink safety
32
+
33
+ Example:
34
+ ```python
35
+ reader = FileReaderTool(
36
+ sandbox_paths=["/data/docs", "/data/configs"],
37
+ allowed_extensions=[".txt", ".json", ".yaml", ".md"],
38
+ max_file_size=1_000_000 # 1MB
39
+ )
40
+
41
+ # Register with ATR
42
+ registry.register(reader.read_file)
43
+ registry.register(reader.list_directory)
44
+
45
+ # Use from agent
46
+ content = reader.read_file("/data/docs/readme.txt")
47
+ ```
48
+ """
49
+
50
+ def __init__(
51
+ self,
52
+ sandbox_paths: Optional[List[str]] = None,
53
+ allowed_extensions: Optional[List[str]] = None,
54
+ blocked_extensions: Optional[List[str]] = None,
55
+ max_file_size: int = 10_000_000, # 10MB
56
+ follow_symlinks: bool = False,
57
+ encoding: str = "utf-8"
58
+ ):
59
+ """
60
+ Initialize file reader tool.
61
+
62
+ Args:
63
+ sandbox_paths: List of allowed directory paths
64
+ allowed_extensions: Whitelist of file extensions (e.g., [".txt", ".json"])
65
+ blocked_extensions: Blacklist of extensions (e.g., [".exe", ".sh"])
66
+ max_file_size: Maximum file size to read in bytes
67
+ follow_symlinks: Whether to follow symbolic links
68
+ encoding: Default file encoding
69
+ """
70
+ self.sandbox_paths: List[Path] = [
71
+ Path(p).resolve() for p in (sandbox_paths or [os.getcwd()])
72
+ ]
73
+ self.allowed_extensions: Optional[Set[str]] = (
74
+ set(ext.lower() for ext in allowed_extensions) if allowed_extensions else None
75
+ )
76
+ self.blocked_extensions: Set[str] = set(
77
+ ext.lower() for ext in (blocked_extensions or [
78
+ ".exe", ".dll", ".so", ".dylib",
79
+ ".sh", ".bash", ".zsh", ".fish",
80
+ ".bat", ".cmd", ".ps1",
81
+ ".py", ".pyc", ".pyo",
82
+ ".class", ".jar",
83
+ ])
84
+ )
85
+ self.max_file_size = max_file_size
86
+ self.follow_symlinks = follow_symlinks
87
+ self.encoding = encoding
88
+
89
+ def _validate_path(self, path: str) -> Path:
90
+ """Validate path is within sandbox and safe to access."""
91
+ # Convert to Path and resolve
92
+ file_path = Path(path)
93
+
94
+ # Don't resolve symlinks if not allowed
95
+ if self.follow_symlinks:
96
+ resolved = file_path.resolve()
97
+ else:
98
+ # Resolve parent but not the file itself if it's a symlink
99
+ resolved = file_path.parent.resolve() / file_path.name
100
+ if file_path.is_symlink():
101
+ raise ValueError(f"Symbolic links not allowed: {path}")
102
+
103
+ # Check for directory traversal attempts
104
+ path_str = str(path)
105
+ if ".." in path_str:
106
+ raise ValueError(f"Directory traversal not allowed: {path}")
107
+
108
+ # Check if within sandbox
109
+ in_sandbox = False
110
+ for sandbox in self.sandbox_paths:
111
+ try:
112
+ resolved.relative_to(sandbox)
113
+ in_sandbox = True
114
+ break
115
+ except ValueError:
116
+ continue
117
+
118
+ if not in_sandbox:
119
+ raise ValueError(
120
+ f"Path '{path}' is outside allowed directories. "
121
+ f"Allowed: {[str(p) for p in self.sandbox_paths]}"
122
+ )
123
+
124
+ return resolved
125
+
126
+ def _validate_extension(self, path: Path):
127
+ """Validate file extension."""
128
+ ext = path.suffix.lower()
129
+
130
+ # Check blocked extensions
131
+ if ext in self.blocked_extensions:
132
+ raise ValueError(f"File extension '{ext}' is blocked")
133
+
134
+ # Check allowed extensions (if whitelist set)
135
+ if self.allowed_extensions and ext not in self.allowed_extensions:
136
+ raise ValueError(
137
+ f"File extension '{ext}' not allowed. "
138
+ f"Allowed: {', '.join(sorted(self.allowed_extensions))}"
139
+ )
140
+
141
+ @tool(
142
+ name="read_file",
143
+ description="Read the contents of a text file",
144
+ tags=["file", "read", "safe"]
145
+ )
146
+ def read_file(
147
+ self,
148
+ path: str,
149
+ encoding: Optional[str] = None,
150
+ max_lines: Optional[int] = None
151
+ ) -> Dict[str, Any]:
152
+ """
153
+ Read a file's contents.
154
+
155
+ Args:
156
+ path: Path to file (must be within sandbox)
157
+ encoding: File encoding (default: utf-8)
158
+ max_lines: Maximum number of lines to read
159
+
160
+ Returns:
161
+ Dict with content, size, and metadata
162
+ """
163
+ # Validate path
164
+ file_path = self._validate_path(path)
165
+ self._validate_extension(file_path)
166
+
167
+ # Check file exists
168
+ if not file_path.exists():
169
+ raise FileNotFoundError(f"File not found: {path}")
170
+
171
+ if not file_path.is_file():
172
+ raise ValueError(f"Path is not a file: {path}")
173
+
174
+ # Check file size
175
+ file_size = file_path.stat().st_size
176
+ if file_size > self.max_file_size:
177
+ raise ValueError(
178
+ f"File too large: {file_size} bytes. "
179
+ f"Maximum: {self.max_file_size} bytes"
180
+ )
181
+
182
+ # Read file
183
+ enc = encoding or self.encoding
184
+ try:
185
+ content = file_path.read_text(encoding=enc)
186
+ except UnicodeDecodeError:
187
+ raise ValueError(f"Unable to decode file with encoding '{enc}'")
188
+
189
+ # Apply line limit
190
+ if max_lines:
191
+ lines = content.splitlines(keepends=True)
192
+ if len(lines) > max_lines:
193
+ content = "".join(lines[:max_lines])
194
+ content += f"\n... [truncated, showing {max_lines} of {len(lines)} lines]"
195
+
196
+ return {
197
+ "content": content,
198
+ "size": file_size,
199
+ "path": str(file_path),
200
+ "encoding": enc,
201
+ "lines": content.count("\n") + 1
202
+ }
203
+
204
+ @tool(
205
+ name="read_file_lines",
206
+ description="Read specific lines from a file",
207
+ tags=["file", "read", "safe"]
208
+ )
209
+ def read_lines(
210
+ self,
211
+ path: str,
212
+ start_line: int = 1,
213
+ end_line: Optional[int] = None,
214
+ encoding: Optional[str] = None
215
+ ) -> Dict[str, Any]:
216
+ """
217
+ Read specific lines from a file.
218
+
219
+ Args:
220
+ path: Path to file
221
+ start_line: First line to read (1-indexed)
222
+ end_line: Last line to read (inclusive, None for end of file)
223
+ encoding: File encoding
224
+
225
+ Returns:
226
+ Dict with lines, content, and metadata
227
+ """
228
+ file_path = self._validate_path(path)
229
+ self._validate_extension(file_path)
230
+
231
+ if not file_path.exists():
232
+ raise FileNotFoundError(f"File not found: {path}")
233
+
234
+ if start_line < 1:
235
+ raise ValueError("start_line must be >= 1")
236
+
237
+ enc = encoding or self.encoding
238
+ lines = file_path.read_text(encoding=enc).splitlines()
239
+
240
+ # Adjust for 0-indexing
241
+ start_idx = start_line - 1
242
+ end_idx = end_line if end_line else len(lines)
243
+
244
+ selected = lines[start_idx:end_idx]
245
+
246
+ return {
247
+ "lines": selected,
248
+ "content": "\n".join(selected),
249
+ "start_line": start_line,
250
+ "end_line": min(end_idx, len(lines)),
251
+ "total_lines": len(lines),
252
+ "path": str(file_path)
253
+ }
254
+
255
+ @tool(
256
+ name="list_directory",
257
+ description="List files and directories in a path",
258
+ tags=["file", "directory", "safe"]
259
+ )
260
+ def list_directory(
261
+ self,
262
+ path: str,
263
+ pattern: str = "*",
264
+ recursive: bool = False,
265
+ include_hidden: bool = False
266
+ ) -> Dict[str, Any]:
267
+ """
268
+ List directory contents.
269
+
270
+ Args:
271
+ path: Directory path
272
+ pattern: Glob pattern (e.g., "*.txt")
273
+ recursive: Whether to search recursively
274
+ include_hidden: Include hidden files (starting with .)
275
+
276
+ Returns:
277
+ Dict with files, directories, and counts
278
+ """
279
+ dir_path = self._validate_path(path)
280
+
281
+ if not dir_path.exists():
282
+ raise FileNotFoundError(f"Directory not found: {path}")
283
+
284
+ if not dir_path.is_dir():
285
+ raise ValueError(f"Path is not a directory: {path}")
286
+
287
+ # List contents
288
+ if recursive:
289
+ matches = list(dir_path.rglob(pattern))
290
+ else:
291
+ matches = list(dir_path.glob(pattern))
292
+
293
+ files = []
294
+ directories = []
295
+
296
+ for item in matches:
297
+ # Skip hidden files unless requested
298
+ if not include_hidden and item.name.startswith("."):
299
+ continue
300
+
301
+ # Skip symlinks if not following
302
+ if item.is_symlink() and not self.follow_symlinks:
303
+ continue
304
+
305
+ rel_path = str(item.relative_to(dir_path))
306
+
307
+ if item.is_file():
308
+ files.append({
309
+ "name": item.name,
310
+ "path": rel_path,
311
+ "size": item.stat().st_size,
312
+ "extension": item.suffix
313
+ })
314
+ elif item.is_dir():
315
+ directories.append({
316
+ "name": item.name,
317
+ "path": rel_path
318
+ })
319
+
320
+ return {
321
+ "path": str(dir_path),
322
+ "files": files,
323
+ "directories": directories,
324
+ "file_count": len(files),
325
+ "directory_count": len(directories)
326
+ }
327
+
328
+ @tool(
329
+ name="file_exists",
330
+ description="Check if a file or directory exists",
331
+ tags=["file", "check", "safe"]
332
+ )
333
+ def exists(self, path: str) -> Dict[str, Any]:
334
+ """
335
+ Check if path exists.
336
+
337
+ Args:
338
+ path: Path to check
339
+
340
+ Returns:
341
+ Dict with exists, is_file, is_dir
342
+ """
343
+ try:
344
+ file_path = self._validate_path(path)
345
+ return {
346
+ "exists": file_path.exists(),
347
+ "is_file": file_path.is_file(),
348
+ "is_directory": file_path.is_dir(),
349
+ "path": str(file_path)
350
+ }
351
+ except ValueError:
352
+ # Path outside sandbox
353
+ return {
354
+ "exists": False,
355
+ "is_file": False,
356
+ "is_directory": False,
357
+ "path": path,
358
+ "error": "Path outside allowed directories"
359
+ }
360
+
361
+ @tool(
362
+ name="file_info",
363
+ description="Get metadata about a file",
364
+ tags=["file", "metadata", "safe"]
365
+ )
366
+ def file_info(self, path: str) -> Dict[str, Any]:
367
+ """
368
+ Get file metadata.
369
+
370
+ Args:
371
+ path: Path to file
372
+
373
+ Returns:
374
+ Dict with size, modified time, etc.
375
+ """
376
+ file_path = self._validate_path(path)
377
+
378
+ if not file_path.exists():
379
+ raise FileNotFoundError(f"File not found: {path}")
380
+
381
+ stat = file_path.stat()
382
+
383
+ return {
384
+ "path": str(file_path),
385
+ "name": file_path.name,
386
+ "extension": file_path.suffix,
387
+ "size": stat.st_size,
388
+ "size_human": self._human_size(stat.st_size),
389
+ "modified": stat.st_mtime,
390
+ "created": stat.st_ctime,
391
+ "is_file": file_path.is_file(),
392
+ "is_directory": file_path.is_dir(),
393
+ "is_symlink": file_path.is_symlink()
394
+ }
395
+
396
+ def _human_size(self, size: int) -> str:
397
+ """Convert bytes to human readable string."""
398
+ for unit in ["B", "KB", "MB", "GB"]:
399
+ if size < 1024:
400
+ return f"{size:.1f} {unit}"
401
+ size /= 1024
402
+ return f"{size:.1f} TB"