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,467 @@
1
+ # Copyright (c) Microsoft Corporation.
2
+ # Licensed under the MIT License.
3
+ """
4
+ Safe Calculator Tool.
5
+
6
+ Provides safe mathematical operations with:
7
+ - No eval() or exec() usage
8
+ - Expression parsing with allowed operations only
9
+ - Overflow protection
10
+ - Timeout for complex calculations
11
+ """
12
+
13
+ import ast
14
+ import math
15
+ import operator
16
+ import re
17
+ from typing import Any, Dict, List, Optional, Union
18
+
19
+ from atr.decorator import tool
20
+
21
+
22
+ class CalculatorTool:
23
+ """
24
+ Safe calculator with expression evaluation.
25
+
26
+ Features:
27
+ - No eval()/exec() - uses safe expression parser
28
+ - Whitelisted operations only
29
+ - Overflow/underflow protection
30
+ - Precision control
31
+ - Common math functions (sqrt, sin, cos, log, etc.)
32
+
33
+ Example:
34
+ ```python
35
+ calc = CalculatorTool(precision=10)
36
+
37
+ # Basic arithmetic
38
+ result = calc.evaluate("2 + 2 * 3") # 8
39
+
40
+ # With variables
41
+ result = calc.evaluate("x * 2 + y", {"x": 5, "y": 10}) # 20
42
+
43
+ # Math functions
44
+ result = calc.evaluate("sqrt(16) + sin(0)") # 4.0
45
+ ```
46
+ """
47
+
48
+ # Allowed operators
49
+ OPERATORS = {
50
+ '+': operator.add,
51
+ '-': operator.sub,
52
+ '*': operator.mul,
53
+ '/': operator.truediv,
54
+ '//': operator.floordiv,
55
+ '%': operator.mod,
56
+ '**': operator.pow,
57
+ '^': operator.pow, # Alias for **
58
+ }
59
+
60
+ # Allowed functions
61
+ FUNCTIONS = {
62
+ 'abs': abs,
63
+ 'round': round,
64
+ 'min': min,
65
+ 'max': max,
66
+ 'sum': sum,
67
+ # Math functions
68
+ 'sqrt': math.sqrt,
69
+ 'pow': math.pow,
70
+ 'exp': math.exp,
71
+ 'log': math.log,
72
+ 'log10': math.log10,
73
+ 'log2': math.log2,
74
+ 'sin': math.sin,
75
+ 'cos': math.cos,
76
+ 'tan': math.tan,
77
+ 'asin': math.asin,
78
+ 'acos': math.acos,
79
+ 'atan': math.atan,
80
+ 'sinh': math.sinh,
81
+ 'cosh': math.cosh,
82
+ 'tanh': math.tanh,
83
+ 'ceil': math.ceil,
84
+ 'floor': math.floor,
85
+ 'factorial': math.factorial,
86
+ 'gcd': math.gcd,
87
+ 'degrees': math.degrees,
88
+ 'radians': math.radians,
89
+ }
90
+
91
+ # Constants
92
+ CONSTANTS = {
93
+ 'pi': math.pi,
94
+ 'e': math.e,
95
+ 'tau': math.tau,
96
+ 'inf': math.inf,
97
+ }
98
+
99
+ def __init__(
100
+ self,
101
+ precision: int = 15,
102
+ max_value: float = 1e308,
103
+ allow_complex: bool = False
104
+ ):
105
+ """
106
+ Initialize calculator.
107
+
108
+ Args:
109
+ precision: Decimal precision for results
110
+ max_value: Maximum allowed value
111
+ allow_complex: Whether to allow complex numbers
112
+ """
113
+ self.precision = precision
114
+ self.max_value = max_value
115
+ self.allow_complex = allow_complex
116
+
117
+ # AST operator mapping for safe evaluation
118
+ _AST_OPS = {
119
+ ast.Add: operator.add,
120
+ ast.Sub: operator.sub,
121
+ ast.Mult: operator.mul,
122
+ ast.Div: operator.truediv,
123
+ ast.FloorDiv: operator.floordiv,
124
+ ast.Mod: operator.mod,
125
+ ast.Pow: operator.pow,
126
+ }
127
+
128
+ _AST_UNARY_OPS = {
129
+ ast.USub: operator.neg,
130
+ ast.UAdd: operator.pos,
131
+ }
132
+
133
+ def _safe_eval_node(
134
+ self,
135
+ node: ast.AST,
136
+ namespace: Dict[str, Any],
137
+ ) -> Any:
138
+ """Recursively evaluate an AST node using only safe operations.
139
+
140
+ No eval()/compile() — walks the AST tree and computes results
141
+ using whitelisted operators and functions only.
142
+ """
143
+ if isinstance(node, ast.Expression):
144
+ return self._safe_eval_node(node.body, namespace)
145
+
146
+ if isinstance(node, ast.Constant):
147
+ if isinstance(node.value, (int, float)):
148
+ return node.value
149
+ raise ValueError(f"Unsupported constant type: {type(node.value).__name__}")
150
+
151
+ if isinstance(node, ast.Name):
152
+ if node.id in namespace:
153
+ return namespace[node.id]
154
+ raise ValueError(f"Unknown variable: {node.id}")
155
+
156
+ if isinstance(node, ast.BinOp):
157
+ left = self._safe_eval_node(node.left, namespace)
158
+ right = self._safe_eval_node(node.right, namespace)
159
+ op_func = self._AST_OPS.get(type(node.op))
160
+ if op_func is None:
161
+ raise ValueError(f"Unsupported operator: {type(node.op).__name__}")
162
+ return op_func(left, right)
163
+
164
+ if isinstance(node, ast.UnaryOp):
165
+ operand = self._safe_eval_node(node.operand, namespace)
166
+ op_func = self._AST_UNARY_OPS.get(type(node.op))
167
+ if op_func is None:
168
+ raise ValueError(f"Unsupported unary operator: {type(node.op).__name__}")
169
+ return op_func(operand)
170
+
171
+ if isinstance(node, ast.Call):
172
+ if not isinstance(node.func, ast.Name):
173
+ raise ValueError("Only direct function calls are allowed (no attribute access)")
174
+ func_name = node.func.id
175
+ if func_name not in self.FUNCTIONS:
176
+ raise ValueError(f"Function not allowed: {func_name}")
177
+ func = self.FUNCTIONS[func_name]
178
+ args = [self._safe_eval_node(arg, namespace) for arg in node.args]
179
+ if node.keywords:
180
+ raise ValueError("Keyword arguments are not supported in function calls")
181
+ return func(*args)
182
+
183
+ if isinstance(node, ast.Tuple):
184
+ return tuple(self._safe_eval_node(elt, namespace) for elt in node.elts)
185
+
186
+ if isinstance(node, ast.List):
187
+ return [self._safe_eval_node(elt, namespace) for elt in node.elts]
188
+
189
+ raise ValueError(f"Unsupported expression type: {type(node).__name__}")
190
+
191
+ def _check_value(self, value: Union[int, float]) -> Union[int, float]:
192
+ """Check value is within bounds."""
193
+ if isinstance(value, complex) and not self.allow_complex:
194
+ raise ValueError("Complex numbers not allowed")
195
+
196
+ if isinstance(value, (int, float)):
197
+ if abs(value) > self.max_value:
198
+ raise OverflowError(f"Value exceeds maximum: {self.max_value}")
199
+
200
+ return value
201
+
202
+ @tool(
203
+ name="calculate",
204
+ description="Evaluate a mathematical expression safely",
205
+ tags=["math", "calculate", "safe"]
206
+ )
207
+ def evaluate(
208
+ self,
209
+ expression: str,
210
+ variables: Optional[Dict[str, Union[int, float]]] = None
211
+ ) -> Dict[str, Any]:
212
+ """
213
+ Evaluate a mathematical expression.
214
+
215
+ Args:
216
+ expression: Math expression (e.g., "2 + 2 * 3")
217
+ variables: Variable values (e.g., {"x": 5})
218
+
219
+ Returns:
220
+ Dict with result and metadata
221
+ """
222
+ variables = variables or {}
223
+
224
+ # Validate expression length
225
+ if len(expression) > 1000:
226
+ return {
227
+ "success": False,
228
+ "error": "Expression too long (max 1000 chars)",
229
+ "result": None
230
+ }
231
+
232
+ # Sanitize - only allow safe characters
233
+ allowed_chars = set("0123456789.+-*/^%() ,")
234
+ allowed_chars.update(set("abcdefghijklmnopqrstuvwxyz_"))
235
+
236
+ clean_expr = expression.lower()
237
+ for char in clean_expr:
238
+ if char not in allowed_chars:
239
+ return {
240
+ "success": False,
241
+ "error": f"Invalid character: '{char}'",
242
+ "result": None
243
+ }
244
+
245
+ try:
246
+ # Build safe namespace
247
+ namespace = {}
248
+ namespace.update(self.CONSTANTS)
249
+ namespace.update(self.FUNCTIONS)
250
+ namespace.update(variables)
251
+
252
+ # Parse and evaluate using safe AST walker
253
+
254
+ # Replace ^ with ** for power
255
+ clean_expr = clean_expr.replace('^', '**')
256
+
257
+ # Parse expression
258
+ tree = ast.parse(clean_expr, mode='eval')
259
+
260
+ # Validate AST nodes
261
+ for node in ast.walk(tree):
262
+ if isinstance(node, ast.Call):
263
+ if isinstance(node.func, ast.Name):
264
+ if node.func.id not in self.FUNCTIONS:
265
+ return {
266
+ "success": False,
267
+ "error": f"Function not allowed: {node.func.id}",
268
+ "result": None
269
+ }
270
+ else:
271
+ return {
272
+ "success": False,
273
+ "error": "Only direct function calls are allowed (no attribute access)",
274
+ "result": None
275
+ }
276
+ elif isinstance(node, ast.Name):
277
+ if node.id not in namespace:
278
+ return {
279
+ "success": False,
280
+ "error": f"Unknown variable: {node.id}",
281
+ "result": None
282
+ }
283
+ elif isinstance(node, ast.Attribute):
284
+ return {
285
+ "success": False,
286
+ "error": "Attribute access is not allowed",
287
+ "result": None
288
+ }
289
+
290
+ # Evaluate using safe AST walker (no eval/compile)
291
+ result = self._safe_eval_node(tree.body, namespace)
292
+
293
+ # Check result
294
+ result = self._check_value(result)
295
+
296
+ # Round if float
297
+ if isinstance(result, float):
298
+ result = round(result, self.precision)
299
+
300
+ return {
301
+ "success": True,
302
+ "result": result,
303
+ "expression": expression,
304
+ "type": type(result).__name__
305
+ }
306
+
307
+ except SyntaxError as e:
308
+ return {
309
+ "success": False,
310
+ "error": f"Syntax error: {e}",
311
+ "result": None
312
+ }
313
+ except (ValueError, TypeError, OverflowError, ZeroDivisionError) as e:
314
+ return {
315
+ "success": False,
316
+ "error": str(e),
317
+ "result": None
318
+ }
319
+ except Exception as e:
320
+ return {
321
+ "success": False,
322
+ "error": f"Calculation error: {e}",
323
+ "result": None
324
+ }
325
+
326
+ @tool(
327
+ name="add",
328
+ description="Add two or more numbers",
329
+ tags=["math", "arithmetic", "safe"]
330
+ )
331
+ def add(self, *numbers: Union[int, float]) -> Dict[str, Any]:
332
+ """Add numbers."""
333
+ try:
334
+ result = sum(numbers)
335
+ return {"success": True, "result": self._check_value(result)}
336
+ except Exception as e:
337
+ return {"success": False, "error": str(e), "result": None}
338
+
339
+ @tool(
340
+ name="subtract",
341
+ description="Subtract numbers (a - b - c - ...)",
342
+ tags=["math", "arithmetic", "safe"]
343
+ )
344
+ def subtract(self, *numbers: Union[int, float]) -> Dict[str, Any]:
345
+ """Subtract numbers."""
346
+ try:
347
+ if not numbers:
348
+ return {"success": False, "error": "No numbers provided", "result": None}
349
+ result = numbers[0]
350
+ for n in numbers[1:]:
351
+ result -= n
352
+ return {"success": True, "result": self._check_value(result)}
353
+ except Exception as e:
354
+ return {"success": False, "error": str(e), "result": None}
355
+
356
+ @tool(
357
+ name="multiply",
358
+ description="Multiply numbers",
359
+ tags=["math", "arithmetic", "safe"]
360
+ )
361
+ def multiply(self, *numbers: Union[int, float]) -> Dict[str, Any]:
362
+ """Multiply numbers."""
363
+ try:
364
+ result = 1
365
+ for n in numbers:
366
+ result *= n
367
+ return {"success": True, "result": self._check_value(result)}
368
+ except Exception as e:
369
+ return {"success": False, "error": str(e), "result": None}
370
+
371
+ @tool(
372
+ name="divide",
373
+ description="Divide numbers (a / b)",
374
+ tags=["math", "arithmetic", "safe"]
375
+ )
376
+ def divide(self, a: Union[int, float], b: Union[int, float]) -> Dict[str, Any]:
377
+ """Divide a by b."""
378
+ try:
379
+ if b == 0:
380
+ return {"success": False, "error": "Division by zero", "result": None}
381
+ result = a / b
382
+ return {"success": True, "result": round(self._check_value(result), self.precision)}
383
+ except Exception as e:
384
+ return {"success": False, "error": str(e), "result": None}
385
+
386
+ @tool(
387
+ name="power",
388
+ description="Calculate a raised to power b (a^b)",
389
+ tags=["math", "arithmetic", "safe"]
390
+ )
391
+ def power(self, base: Union[int, float], exponent: Union[int, float]) -> Dict[str, Any]:
392
+ """Calculate power."""
393
+ try:
394
+ # Limit exponent to prevent huge calculations
395
+ if abs(exponent) > 1000:
396
+ return {"success": False, "error": "Exponent too large", "result": None}
397
+ result = base ** exponent
398
+ return {"success": True, "result": self._check_value(result)}
399
+ except Exception as e:
400
+ return {"success": False, "error": str(e), "result": None}
401
+
402
+ @tool(
403
+ name="sqrt",
404
+ description="Calculate square root",
405
+ tags=["math", "safe"]
406
+ )
407
+ def sqrt(self, n: Union[int, float]) -> Dict[str, Any]:
408
+ """Calculate square root."""
409
+ try:
410
+ if n < 0 and not self.allow_complex:
411
+ return {"success": False, "error": "Cannot take sqrt of negative number", "result": None}
412
+ result = math.sqrt(n)
413
+ return {"success": True, "result": round(result, self.precision)}
414
+ except Exception as e:
415
+ return {"success": False, "error": str(e), "result": None}
416
+
417
+ @tool(
418
+ name="percentage",
419
+ description="Calculate percentage (what is x% of y)",
420
+ tags=["math", "percentage", "safe"]
421
+ )
422
+ def percentage(self, percent: Union[int, float], of_value: Union[int, float]) -> Dict[str, Any]:
423
+ """Calculate percentage."""
424
+ try:
425
+ result = (percent / 100) * of_value
426
+ return {
427
+ "success": True,
428
+ "result": round(result, self.precision),
429
+ "description": f"{percent}% of {of_value} = {round(result, self.precision)}"
430
+ }
431
+ except Exception as e:
432
+ return {"success": False, "error": str(e), "result": None}
433
+
434
+ @tool(
435
+ name="statistics",
436
+ description="Calculate basic statistics (mean, median, std dev)",
437
+ tags=["math", "statistics", "safe"]
438
+ )
439
+ def statistics(self, numbers: List[Union[int, float]]) -> Dict[str, Any]:
440
+ """Calculate basic statistics."""
441
+ try:
442
+ if not numbers:
443
+ return {"success": False, "error": "No numbers provided", "result": None}
444
+
445
+ import statistics as stats
446
+
447
+ n = len(numbers)
448
+ mean = stats.mean(numbers)
449
+ median = stats.median(numbers)
450
+
451
+ result = {
452
+ "count": n,
453
+ "sum": sum(numbers),
454
+ "mean": round(mean, self.precision),
455
+ "median": round(median, self.precision),
456
+ "min": min(numbers),
457
+ "max": max(numbers),
458
+ }
459
+
460
+ if n > 1:
461
+ result["std_dev"] = round(stats.stdev(numbers), self.precision)
462
+ result["variance"] = round(stats.variance(numbers), self.precision)
463
+
464
+ return {"success": True, "result": result}
465
+
466
+ except Exception as e:
467
+ return {"success": False, "error": str(e), "result": None}