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,443 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Safe DateTime Tool.
5
+
6
+ Provides timezone-aware datetime operations with:
7
+ - Safe parsing (no arbitrary code)
8
+ - Timezone support
9
+ - Human-readable formatting
10
+ - Date arithmetic
11
+ """
12
+
13
+ from datetime import datetime, timedelta, timezone
14
+ from typing import Any, Dict, List, Optional, Union
15
+
16
+ from atr.decorator import tool
17
+
18
+
19
+ class DateTimeTool:
20
+ """
21
+ Safe datetime operations.
22
+
23
+ Features:
24
+ - Timezone-aware operations
25
+ - Safe date parsing
26
+ - Human-readable formatting
27
+ - Date arithmetic
28
+ - No eval() or exec()
29
+
30
+ Example:
31
+ ```python
32
+ dt = DateTimeTool(default_timezone="UTC")
33
+
34
+ # Get current time
35
+ now = dt.now()
36
+
37
+ # Parse date
38
+ date = dt.parse("2024-01-15T10:30:00Z")
39
+
40
+ # Format date
41
+ formatted = dt.format(date, "YYYY-MM-DD")
42
+
43
+ # Add/subtract time
44
+ future = dt.add(date, days=7, hours=2)
45
+ ```
46
+ """
47
+
48
+ # Common format patterns
49
+ FORMATS = {
50
+ "iso": "%Y-%m-%dT%H:%M:%S%z",
51
+ "date": "%Y-%m-%d",
52
+ "time": "%H:%M:%S",
53
+ "datetime": "%Y-%m-%d %H:%M:%S",
54
+ "human": "%B %d, %Y at %I:%M %p",
55
+ "short": "%m/%d/%Y",
56
+ "rfc2822": "%a, %d %b %Y %H:%M:%S %z",
57
+ }
58
+
59
+ def __init__(self, default_timezone: str = "UTC"):
60
+ """
61
+ Initialize datetime tool.
62
+
63
+ Args:
64
+ default_timezone: Default timezone name
65
+ """
66
+ self.default_timezone = default_timezone
67
+ self._tz_cache = {}
68
+
69
+ def _get_timezone(self, tz_name: Optional[str] = None) -> timezone:
70
+ """Get timezone object."""
71
+ tz_name = tz_name or self.default_timezone
72
+
73
+ if tz_name in self._tz_cache:
74
+ return self._tz_cache[tz_name]
75
+
76
+ # Try to get timezone
77
+ if tz_name.upper() == "UTC":
78
+ tz = timezone.utc
79
+ else:
80
+ try:
81
+ import zoneinfo
82
+ tz = zoneinfo.ZoneInfo(tz_name)
83
+ except ImportError:
84
+ # Fallback to UTC offset parsing
85
+ if tz_name.startswith("+") or tz_name.startswith("-"):
86
+ hours = int(tz_name[:3])
87
+ minutes = int(tz_name[4:6]) if len(tz_name) > 4 else 0
88
+ tz = timezone(timedelta(hours=hours, minutes=minutes))
89
+ else:
90
+ tz = timezone.utc
91
+
92
+ self._tz_cache[tz_name] = tz
93
+ return tz
94
+
95
+ @tool(
96
+ name="datetime_now",
97
+ description="Get the current date and time",
98
+ tags=["datetime", "safe"]
99
+ )
100
+ def now(self, timezone_name: Optional[str] = None) -> Dict[str, Any]:
101
+ """
102
+ Get current datetime.
103
+
104
+ Args:
105
+ timezone_name: Timezone name (default: UTC)
106
+
107
+ Returns:
108
+ Dict with current datetime info
109
+ """
110
+ try:
111
+ tz = self._get_timezone(timezone_name)
112
+ now = datetime.now(tz)
113
+
114
+ return {
115
+ "success": True,
116
+ "iso": now.isoformat(),
117
+ "timestamp": now.timestamp(),
118
+ "year": now.year,
119
+ "month": now.month,
120
+ "day": now.day,
121
+ "hour": now.hour,
122
+ "minute": now.minute,
123
+ "second": now.second,
124
+ "weekday": now.strftime("%A"),
125
+ "timezone": str(tz)
126
+ }
127
+ except Exception as e:
128
+ return {"success": False, "error": str(e)}
129
+
130
+ @tool(
131
+ name="datetime_parse",
132
+ description="Parse a date/time string into components",
133
+ tags=["datetime", "parse", "safe"]
134
+ )
135
+ def parse(
136
+ self,
137
+ date_string: str,
138
+ format: Optional[str] = None
139
+ ) -> Dict[str, Any]:
140
+ """
141
+ Parse datetime string.
142
+
143
+ Args:
144
+ date_string: Date string to parse
145
+ format: Optional strptime format or preset name
146
+
147
+ Returns:
148
+ Dict with parsed datetime
149
+ """
150
+ try:
151
+ # Try preset formats first
152
+ if format and format.lower() in self.FORMATS:
153
+ fmt = self.FORMATS[format.lower()]
154
+ dt = datetime.strptime(date_string, fmt)
155
+ elif format:
156
+ dt = datetime.strptime(date_string, format)
157
+ else:
158
+ # Try common formats
159
+ for fmt in [
160
+ "%Y-%m-%dT%H:%M:%S%z",
161
+ "%Y-%m-%dT%H:%M:%SZ",
162
+ "%Y-%m-%dT%H:%M:%S",
163
+ "%Y-%m-%d %H:%M:%S",
164
+ "%Y-%m-%d",
165
+ "%m/%d/%Y",
166
+ "%d/%m/%Y",
167
+ "%B %d, %Y",
168
+ ]:
169
+ try:
170
+ dt = datetime.strptime(date_string, fmt)
171
+ break
172
+ except ValueError:
173
+ continue
174
+ else:
175
+ return {
176
+ "success": False,
177
+ "error": f"Could not parse date: {date_string}"
178
+ }
179
+
180
+ # Ensure timezone
181
+ if dt.tzinfo is None:
182
+ dt = dt.replace(tzinfo=self._get_timezone())
183
+
184
+ return {
185
+ "success": True,
186
+ "iso": dt.isoformat(),
187
+ "timestamp": dt.timestamp(),
188
+ "year": dt.year,
189
+ "month": dt.month,
190
+ "day": dt.day,
191
+ "hour": dt.hour,
192
+ "minute": dt.minute,
193
+ "second": dt.second,
194
+ "weekday": dt.strftime("%A")
195
+ }
196
+
197
+ except Exception as e:
198
+ return {"success": False, "error": str(e)}
199
+
200
+ @tool(
201
+ name="datetime_format",
202
+ description="Format a datetime into a string",
203
+ tags=["datetime", "format", "safe"]
204
+ )
205
+ def format(
206
+ self,
207
+ iso_datetime: str,
208
+ format: str = "human"
209
+ ) -> Dict[str, Any]:
210
+ """
211
+ Format datetime to string.
212
+
213
+ Args:
214
+ iso_datetime: ISO format datetime string
215
+ format: Output format (preset name or strftime format)
216
+
217
+ Returns:
218
+ Dict with formatted string
219
+ """
220
+ try:
221
+ # Parse input
222
+ dt = datetime.fromisoformat(iso_datetime.replace("Z", "+00:00"))
223
+
224
+ # Get format
225
+ if format.lower() in self.FORMATS:
226
+ fmt = self.FORMATS[format.lower()]
227
+ else:
228
+ fmt = format
229
+
230
+ formatted = dt.strftime(fmt)
231
+
232
+ return {
233
+ "success": True,
234
+ "formatted": formatted,
235
+ "format_used": fmt
236
+ }
237
+
238
+ except Exception as e:
239
+ return {"success": False, "error": str(e)}
240
+
241
+ @tool(
242
+ name="datetime_add",
243
+ description="Add time to a datetime",
244
+ tags=["datetime", "arithmetic", "safe"]
245
+ )
246
+ def add(
247
+ self,
248
+ iso_datetime: str,
249
+ years: int = 0,
250
+ months: int = 0,
251
+ weeks: int = 0,
252
+ days: int = 0,
253
+ hours: int = 0,
254
+ minutes: int = 0,
255
+ seconds: int = 0
256
+ ) -> Dict[str, Any]:
257
+ """
258
+ Add time to datetime.
259
+
260
+ Args:
261
+ iso_datetime: ISO format datetime
262
+ years: Years to add
263
+ months: Months to add
264
+ weeks: Weeks to add
265
+ days: Days to add
266
+ hours: Hours to add
267
+ minutes: Minutes to add
268
+ seconds: Seconds to add
269
+
270
+ Returns:
271
+ Dict with new datetime
272
+ """
273
+ try:
274
+ dt = datetime.fromisoformat(iso_datetime.replace("Z", "+00:00"))
275
+
276
+ # Add using timedelta (doesn't handle years/months)
277
+ delta = timedelta(
278
+ weeks=weeks,
279
+ days=days,
280
+ hours=hours,
281
+ minutes=minutes,
282
+ seconds=seconds
283
+ )
284
+
285
+ new_dt = dt + delta
286
+
287
+ # Handle years and months manually
288
+ if years or months:
289
+ new_year = new_dt.year + years
290
+ new_month = new_dt.month + months
291
+
292
+ # Handle month overflow
293
+ while new_month > 12:
294
+ new_month -= 12
295
+ new_year += 1
296
+ while new_month < 1:
297
+ new_month += 12
298
+ new_year -= 1
299
+
300
+ # Handle day overflow for short months
301
+ import calendar
302
+ max_day = calendar.monthrange(new_year, new_month)[1]
303
+ new_day = min(new_dt.day, max_day)
304
+
305
+ new_dt = new_dt.replace(year=new_year, month=new_month, day=new_day)
306
+
307
+ return {
308
+ "success": True,
309
+ "original": iso_datetime,
310
+ "result": new_dt.isoformat(),
311
+ "added": {
312
+ "years": years,
313
+ "months": months,
314
+ "weeks": weeks,
315
+ "days": days,
316
+ "hours": hours,
317
+ "minutes": minutes,
318
+ "seconds": seconds
319
+ }
320
+ }
321
+
322
+ except Exception as e:
323
+ return {"success": False, "error": str(e)}
324
+
325
+ @tool(
326
+ name="datetime_diff",
327
+ description="Calculate difference between two datetimes",
328
+ tags=["datetime", "arithmetic", "safe"]
329
+ )
330
+ def diff(
331
+ self,
332
+ datetime1: str,
333
+ datetime2: str
334
+ ) -> Dict[str, Any]:
335
+ """
336
+ Calculate difference between datetimes.
337
+
338
+ Args:
339
+ datetime1: First datetime (ISO format)
340
+ datetime2: Second datetime (ISO format)
341
+
342
+ Returns:
343
+ Dict with difference in various units
344
+ """
345
+ try:
346
+ dt1 = datetime.fromisoformat(datetime1.replace("Z", "+00:00"))
347
+ dt2 = datetime.fromisoformat(datetime2.replace("Z", "+00:00"))
348
+
349
+ delta = dt2 - dt1
350
+ total_seconds = delta.total_seconds()
351
+
352
+ return {
353
+ "success": True,
354
+ "days": delta.days,
355
+ "total_seconds": total_seconds,
356
+ "total_minutes": total_seconds / 60,
357
+ "total_hours": total_seconds / 3600,
358
+ "human_readable": self._format_timedelta(delta)
359
+ }
360
+
361
+ except Exception as e:
362
+ return {"success": False, "error": str(e)}
363
+
364
+ def _format_timedelta(self, delta: timedelta) -> str:
365
+ """Format timedelta as human readable string."""
366
+ total_seconds = int(abs(delta.total_seconds()))
367
+
368
+ days = total_seconds // 86400
369
+ hours = (total_seconds % 86400) // 3600
370
+ minutes = (total_seconds % 3600) // 60
371
+ seconds = total_seconds % 60
372
+
373
+ parts = []
374
+ if days:
375
+ parts.append(f"{days} day{'s' if days != 1 else ''}")
376
+ if hours:
377
+ parts.append(f"{hours} hour{'s' if hours != 1 else ''}")
378
+ if minutes:
379
+ parts.append(f"{minutes} minute{'s' if minutes != 1 else ''}")
380
+ if seconds or not parts:
381
+ parts.append(f"{seconds} second{'s' if seconds != 1 else ''}")
382
+
383
+ result = ", ".join(parts)
384
+ if delta.total_seconds() < 0:
385
+ result = f"-{result}"
386
+
387
+ return result
388
+
389
+ @tool(
390
+ name="datetime_convert_timezone",
391
+ description="Convert datetime to a different timezone",
392
+ tags=["datetime", "timezone", "safe"]
393
+ )
394
+ def convert_timezone(
395
+ self,
396
+ iso_datetime: str,
397
+ to_timezone: str
398
+ ) -> Dict[str, Any]:
399
+ """
400
+ Convert datetime to different timezone.
401
+
402
+ Args:
403
+ iso_datetime: ISO format datetime
404
+ to_timezone: Target timezone name
405
+
406
+ Returns:
407
+ Dict with converted datetime
408
+ """
409
+ try:
410
+ dt = datetime.fromisoformat(iso_datetime.replace("Z", "+00:00"))
411
+ target_tz = self._get_timezone(to_timezone)
412
+
413
+ converted = dt.astimezone(target_tz)
414
+
415
+ return {
416
+ "success": True,
417
+ "original": iso_datetime,
418
+ "converted": converted.isoformat(),
419
+ "timezone": to_timezone
420
+ }
421
+
422
+ except Exception as e:
423
+ return {"success": False, "error": str(e)}
424
+
425
+ @tool(
426
+ name="datetime_is_before",
427
+ description="Check if one datetime is before another",
428
+ tags=["datetime", "compare", "safe"]
429
+ )
430
+ def is_before(self, datetime1: str, datetime2: str) -> Dict[str, Any]:
431
+ """Check if datetime1 is before datetime2."""
432
+ try:
433
+ dt1 = datetime.fromisoformat(datetime1.replace("Z", "+00:00"))
434
+ dt2 = datetime.fromisoformat(datetime2.replace("Z", "+00:00"))
435
+
436
+ return {
437
+ "success": True,
438
+ "result": dt1 < dt2,
439
+ "datetime1": datetime1,
440
+ "datetime2": datetime2
441
+ }
442
+ except Exception as e:
443
+ return {"success": False, "error": str(e)}