onetool-mcp 1.0.0b1__py3-none-any.whl → 1.0.0rc2__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 (81) hide show
  1. onetool/cli.py +63 -4
  2. onetool_mcp-1.0.0rc2.dist-info/METADATA +266 -0
  3. onetool_mcp-1.0.0rc2.dist-info/RECORD +129 -0
  4. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/LICENSE.txt +1 -1
  5. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/NOTICE.txt +54 -64
  6. ot/__main__.py +6 -6
  7. ot/config/__init__.py +48 -46
  8. ot/config/global_templates/__init__.py +2 -2
  9. ot/config/{defaults → global_templates}/diagram-templates/api-flow.mmd +33 -33
  10. ot/config/{defaults → global_templates}/diagram-templates/c4-context.puml +30 -30
  11. ot/config/{defaults → global_templates}/diagram-templates/class-diagram.mmd +87 -87
  12. ot/config/{defaults → global_templates}/diagram-templates/feature-mindmap.mmd +70 -70
  13. ot/config/{defaults → global_templates}/diagram-templates/microservices.d2 +81 -81
  14. ot/config/{defaults → global_templates}/diagram-templates/project-gantt.mmd +37 -37
  15. ot/config/{defaults → global_templates}/diagram-templates/state-machine.mmd +42 -42
  16. ot/config/global_templates/diagram.yaml +167 -0
  17. ot/config/global_templates/onetool.yaml +3 -1
  18. ot/config/{defaults → global_templates}/prompts.yaml +102 -97
  19. ot/config/global_templates/security.yaml +31 -0
  20. ot/config/global_templates/servers.yaml +93 -12
  21. ot/config/global_templates/snippets.yaml +5 -26
  22. ot/config/{defaults → global_templates}/tool_templates/__init__.py +7 -7
  23. ot/config/loader.py +221 -105
  24. ot/config/mcp.py +5 -1
  25. ot/config/secrets.py +192 -190
  26. ot/decorators.py +116 -116
  27. ot/executor/__init__.py +35 -35
  28. ot/executor/base.py +16 -16
  29. ot/executor/fence_processor.py +83 -83
  30. ot/executor/linter.py +142 -142
  31. ot/executor/pep723.py +288 -288
  32. ot/executor/runner.py +20 -6
  33. ot/executor/simple.py +163 -163
  34. ot/executor/validator.py +603 -164
  35. ot/http_client.py +145 -145
  36. ot/logging/__init__.py +37 -37
  37. ot/logging/entry.py +213 -213
  38. ot/logging/format.py +191 -188
  39. ot/logging/span.py +349 -349
  40. ot/meta.py +236 -14
  41. ot/paths.py +32 -49
  42. ot/prompts.py +218 -218
  43. ot/proxy/manager.py +14 -2
  44. ot/registry/__init__.py +189 -189
  45. ot/registry/parser.py +269 -269
  46. ot/server.py +330 -315
  47. ot/shortcuts/__init__.py +15 -15
  48. ot/shortcuts/aliases.py +87 -87
  49. ot/shortcuts/snippets.py +258 -258
  50. ot/stats/__init__.py +35 -35
  51. ot/stats/html.py +2 -2
  52. ot/stats/reader.py +354 -354
  53. ot/stats/timing.py +57 -57
  54. ot/support.py +63 -63
  55. ot/tools.py +1 -1
  56. ot/utils/batch.py +161 -161
  57. ot/utils/cache.py +120 -120
  58. ot/utils/exceptions.py +23 -23
  59. ot/utils/factory.py +178 -179
  60. ot/utils/format.py +65 -65
  61. ot/utils/http.py +202 -202
  62. ot/utils/platform.py +45 -45
  63. ot/utils/truncate.py +69 -69
  64. ot_tools/__init__.py +4 -4
  65. ot_tools/_convert/__init__.py +12 -12
  66. ot_tools/_convert/pdf.py +254 -254
  67. ot_tools/diagram.yaml +167 -167
  68. ot_tools/scaffold.py +2 -2
  69. ot_tools/transform.py +124 -19
  70. ot_tools/web_fetch.py +94 -43
  71. onetool_mcp-1.0.0b1.dist-info/METADATA +0 -163
  72. onetool_mcp-1.0.0b1.dist-info/RECORD +0 -132
  73. ot/config/defaults/bench.yaml +0 -4
  74. ot/config/defaults/onetool.yaml +0 -25
  75. ot/config/defaults/servers.yaml +0 -7
  76. ot/config/defaults/snippets.yaml +0 -4
  77. ot_tools/firecrawl.py +0 -732
  78. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/WHEEL +0 -0
  79. {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/entry_points.txt +0 -0
  80. /ot/config/{defaults → global_templates}/tool_templates/extension.py +0 -0
  81. /ot/config/{defaults → global_templates}/tool_templates/isolated.py +0 -0
ot/executor/simple.py CHANGED
@@ -1,163 +1,163 @@
1
- """Simple executor - host process execution.
2
-
3
- Executes tool code directly in the host Python process.
4
- V1 uses this executor for all execution.
5
- """
6
-
7
- from __future__ import annotations
8
-
9
- import importlib.util
10
- import sys
11
- import time
12
- from typing import TYPE_CHECKING, Any
13
-
14
- from loguru import logger
15
-
16
- from ot.executor.base import ExecutionResult
17
- from ot.logging import LogEntry, LogSpan
18
- from ot.utils import serialize_result
19
-
20
- if TYPE_CHECKING:
21
- from ot.registry import ToolInfo
22
-
23
-
24
- class SimpleExecutor:
25
- """Host process executor (v1 behaviour).
26
-
27
- Loads and executes tool modules directly in the host Python process.
28
- Fast but no isolation - tools have full filesystem access.
29
- """
30
-
31
- @property
32
- def name(self) -> str:
33
- """Return the executor name."""
34
- return "simple"
35
-
36
- def _load_tool_module(self, module_name: str) -> Any:
37
- """Dynamically load a tool module.
38
-
39
- Args:
40
- module_name: Module path like 'tools.example'
41
-
42
- Returns:
43
- The loaded module object
44
-
45
- Raises:
46
- ImportError: If module cannot be loaded
47
- """
48
- from ot.config.loader import get_config
49
-
50
- # Get tool files from config
51
- config = get_config()
52
- tool_files = config.get_tool_files() if config else []
53
- if not tool_files:
54
- raise ImportError(
55
- f"No tool files configured. Cannot load module: {module_name}"
56
- )
57
-
58
- # Convert module path to file name (tools.example -> example.py)
59
- parts = module_name.split(".")
60
- if len(parts) < 2 or parts[-2] != "tools":
61
- raise ImportError(f"Invalid tool module: {module_name}")
62
-
63
- target_name = f"{parts[-1]}.py"
64
-
65
- # Find matching tool file from config
66
- file_path = None
67
- for tf in tool_files:
68
- if tf.name == target_name:
69
- file_path = tf
70
- break
71
-
72
- if file_path is None or not file_path.exists():
73
- raise ImportError(f"Tool file not found: {target_name}")
74
-
75
- # Load the module dynamically
76
- spec = importlib.util.spec_from_file_location(module_name, file_path)
77
- if spec is None or spec.loader is None:
78
- raise ImportError(f"Cannot load module spec for: {file_path}")
79
-
80
- module = importlib.util.module_from_spec(spec)
81
- sys.modules[module_name] = module
82
- spec.loader.exec_module(module)
83
-
84
- return module
85
-
86
- async def execute(
87
- self,
88
- func_name: str,
89
- kwargs: dict[str, Any],
90
- tool: ToolInfo,
91
- ) -> ExecutionResult:
92
- """Execute a tool function in the host process.
93
-
94
- Args:
95
- func_name: Name of the function to execute
96
- kwargs: Keyword arguments for the function
97
- tool: ToolInfo with module and signature info
98
-
99
- Returns:
100
- ExecutionResult with success status and result string
101
- """
102
- start_time = time.perf_counter()
103
-
104
- try:
105
- # Load the module and get the function
106
- module = self._load_tool_module(tool.module)
107
- func = getattr(module, func_name, None)
108
-
109
- if func is None:
110
- raise ValueError(
111
- f"Function '{func_name}' not found in module {tool.module}"
112
- )
113
-
114
- # Execute the function with timing via LogSpan
115
- with LogSpan(span="executor.simple", tool=func_name) as span:
116
- span.add("kwargs", {k: str(v) for k, v in kwargs.items()})
117
- result = func(**kwargs)
118
- result_str = serialize_result(result)
119
- span.add("resultLength", len(result_str))
120
-
121
- duration = time.perf_counter() - start_time
122
-
123
- return ExecutionResult(
124
- success=True,
125
- result=result_str,
126
- duration_seconds=duration,
127
- executor="simple",
128
- )
129
-
130
- except Exception as e:
131
- duration = time.perf_counter() - start_time
132
- logger.error(
133
- LogEntry(
134
- span="executor.simple.error",
135
- tool=func_name,
136
- error=str(e),
137
- errorType=type(e).__name__,
138
- duration=duration,
139
- )
140
- )
141
-
142
- return ExecutionResult(
143
- success=False,
144
- result=f"Error executing tool '{func_name}': {e}",
145
- duration_seconds=duration,
146
- executor="simple",
147
- error_type=type(e).__name__,
148
- )
149
-
150
- async def start(self) -> None:
151
- """Start the executor (no-op for simple executor)."""
152
- logger.debug(LogEntry(span="executor.simple.start"))
153
-
154
- async def stop(self) -> None:
155
- """Stop the executor (no-op for simple executor)."""
156
- logger.debug(LogEntry(span="executor.simple.stop"))
157
-
158
- async def health_check(self) -> bool:
159
- """Check if the executor is healthy.
160
-
161
- Simple executor is always healthy.
162
- """
163
- return True
1
+ """Simple executor - host process execution.
2
+
3
+ Executes tool code directly in the host Python process.
4
+ V1 uses this executor for all execution.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import importlib.util
10
+ import sys
11
+ import time
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ from loguru import logger
15
+
16
+ from ot.executor.base import ExecutionResult
17
+ from ot.logging import LogEntry, LogSpan
18
+ from ot.utils import serialize_result
19
+
20
+ if TYPE_CHECKING:
21
+ from ot.registry import ToolInfo
22
+
23
+
24
+ class SimpleExecutor:
25
+ """Host process executor (v1 behaviour).
26
+
27
+ Loads and executes tool modules directly in the host Python process.
28
+ Fast but no isolation - tools have full filesystem access.
29
+ """
30
+
31
+ @property
32
+ def name(self) -> str:
33
+ """Return the executor name."""
34
+ return "simple"
35
+
36
+ def _load_tool_module(self, module_name: str) -> Any:
37
+ """Dynamically load a tool module.
38
+
39
+ Args:
40
+ module_name: Module path like 'tools.example'
41
+
42
+ Returns:
43
+ The loaded module object
44
+
45
+ Raises:
46
+ ImportError: If module cannot be loaded
47
+ """
48
+ from ot.config.loader import get_config
49
+
50
+ # Get tool files from config
51
+ config = get_config()
52
+ tool_files = config.get_tool_files() if config else []
53
+ if not tool_files:
54
+ raise ImportError(
55
+ f"No tool files configured. Cannot load module: {module_name}"
56
+ )
57
+
58
+ # Convert module path to file name (tools.example -> example.py)
59
+ parts = module_name.split(".")
60
+ if len(parts) < 2 or parts[-2] != "tools":
61
+ raise ImportError(f"Invalid tool module: {module_name}")
62
+
63
+ target_name = f"{parts[-1]}.py"
64
+
65
+ # Find matching tool file from config
66
+ file_path = None
67
+ for tf in tool_files:
68
+ if tf.name == target_name:
69
+ file_path = tf
70
+ break
71
+
72
+ if file_path is None or not file_path.exists():
73
+ raise ImportError(f"Tool file not found: {target_name}")
74
+
75
+ # Load the module dynamically
76
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
77
+ if spec is None or spec.loader is None:
78
+ raise ImportError(f"Cannot load module spec for: {file_path}")
79
+
80
+ module = importlib.util.module_from_spec(spec)
81
+ sys.modules[module_name] = module
82
+ spec.loader.exec_module(module)
83
+
84
+ return module
85
+
86
+ async def execute(
87
+ self,
88
+ func_name: str,
89
+ kwargs: dict[str, Any],
90
+ tool: ToolInfo,
91
+ ) -> ExecutionResult:
92
+ """Execute a tool function in the host process.
93
+
94
+ Args:
95
+ func_name: Name of the function to execute
96
+ kwargs: Keyword arguments for the function
97
+ tool: ToolInfo with module and signature info
98
+
99
+ Returns:
100
+ ExecutionResult with success status and result string
101
+ """
102
+ start_time = time.perf_counter()
103
+
104
+ try:
105
+ # Load the module and get the function
106
+ module = self._load_tool_module(tool.module)
107
+ func = getattr(module, func_name, None)
108
+
109
+ if func is None:
110
+ raise ValueError(
111
+ f"Function '{func_name}' not found in module {tool.module}"
112
+ )
113
+
114
+ # Execute the function with timing via LogSpan
115
+ with LogSpan(span="executor.simple", tool=func_name) as span:
116
+ span.add("kwargs", {k: str(v) for k, v in kwargs.items()})
117
+ result = func(**kwargs)
118
+ result_str = serialize_result(result)
119
+ span.add("resultLength", len(result_str))
120
+
121
+ duration = time.perf_counter() - start_time
122
+
123
+ return ExecutionResult(
124
+ success=True,
125
+ result=result_str,
126
+ duration_seconds=duration,
127
+ executor="simple",
128
+ )
129
+
130
+ except Exception as e:
131
+ duration = time.perf_counter() - start_time
132
+ logger.error(
133
+ LogEntry(
134
+ span="executor.simple.error",
135
+ tool=func_name,
136
+ error=str(e),
137
+ errorType=type(e).__name__,
138
+ duration=duration,
139
+ )
140
+ )
141
+
142
+ return ExecutionResult(
143
+ success=False,
144
+ result=f"Error executing tool '{func_name}': {e}",
145
+ duration_seconds=duration,
146
+ executor="simple",
147
+ error_type=type(e).__name__,
148
+ )
149
+
150
+ async def start(self) -> None:
151
+ """Start the executor (no-op for simple executor)."""
152
+ logger.debug(LogEntry(span="executor.simple.start"))
153
+
154
+ async def stop(self) -> None:
155
+ """Stop the executor (no-op for simple executor)."""
156
+ logger.debug(LogEntry(span="executor.simple.stop"))
157
+
158
+ async def health_check(self) -> bool:
159
+ """Check if the executor is healthy.
160
+
161
+ Simple executor is always healthy.
162
+ """
163
+ return True