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.
- onetool/cli.py +63 -4
- onetool_mcp-1.0.0rc2.dist-info/METADATA +266 -0
- onetool_mcp-1.0.0rc2.dist-info/RECORD +129 -0
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/LICENSE.txt +1 -1
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/licenses/NOTICE.txt +54 -64
- ot/__main__.py +6 -6
- ot/config/__init__.py +48 -46
- ot/config/global_templates/__init__.py +2 -2
- ot/config/{defaults → global_templates}/diagram-templates/api-flow.mmd +33 -33
- ot/config/{defaults → global_templates}/diagram-templates/c4-context.puml +30 -30
- ot/config/{defaults → global_templates}/diagram-templates/class-diagram.mmd +87 -87
- ot/config/{defaults → global_templates}/diagram-templates/feature-mindmap.mmd +70 -70
- ot/config/{defaults → global_templates}/diagram-templates/microservices.d2 +81 -81
- ot/config/{defaults → global_templates}/diagram-templates/project-gantt.mmd +37 -37
- ot/config/{defaults → global_templates}/diagram-templates/state-machine.mmd +42 -42
- ot/config/global_templates/diagram.yaml +167 -0
- ot/config/global_templates/onetool.yaml +3 -1
- ot/config/{defaults → global_templates}/prompts.yaml +102 -97
- ot/config/global_templates/security.yaml +31 -0
- ot/config/global_templates/servers.yaml +93 -12
- ot/config/global_templates/snippets.yaml +5 -26
- ot/config/{defaults → global_templates}/tool_templates/__init__.py +7 -7
- ot/config/loader.py +221 -105
- ot/config/mcp.py +5 -1
- ot/config/secrets.py +192 -190
- ot/decorators.py +116 -116
- ot/executor/__init__.py +35 -35
- ot/executor/base.py +16 -16
- ot/executor/fence_processor.py +83 -83
- ot/executor/linter.py +142 -142
- ot/executor/pep723.py +288 -288
- ot/executor/runner.py +20 -6
- ot/executor/simple.py +163 -163
- ot/executor/validator.py +603 -164
- ot/http_client.py +145 -145
- ot/logging/__init__.py +37 -37
- ot/logging/entry.py +213 -213
- ot/logging/format.py +191 -188
- ot/logging/span.py +349 -349
- ot/meta.py +236 -14
- ot/paths.py +32 -49
- ot/prompts.py +218 -218
- ot/proxy/manager.py +14 -2
- ot/registry/__init__.py +189 -189
- ot/registry/parser.py +269 -269
- ot/server.py +330 -315
- ot/shortcuts/__init__.py +15 -15
- ot/shortcuts/aliases.py +87 -87
- ot/shortcuts/snippets.py +258 -258
- ot/stats/__init__.py +35 -35
- ot/stats/html.py +2 -2
- ot/stats/reader.py +354 -354
- ot/stats/timing.py +57 -57
- ot/support.py +63 -63
- ot/tools.py +1 -1
- ot/utils/batch.py +161 -161
- ot/utils/cache.py +120 -120
- ot/utils/exceptions.py +23 -23
- ot/utils/factory.py +178 -179
- ot/utils/format.py +65 -65
- ot/utils/http.py +202 -202
- ot/utils/platform.py +45 -45
- ot/utils/truncate.py +69 -69
- ot_tools/__init__.py +4 -4
- ot_tools/_convert/__init__.py +12 -12
- ot_tools/_convert/pdf.py +254 -254
- ot_tools/diagram.yaml +167 -167
- ot_tools/scaffold.py +2 -2
- ot_tools/transform.py +124 -19
- ot_tools/web_fetch.py +94 -43
- onetool_mcp-1.0.0b1.dist-info/METADATA +0 -163
- onetool_mcp-1.0.0b1.dist-info/RECORD +0 -132
- ot/config/defaults/bench.yaml +0 -4
- ot/config/defaults/onetool.yaml +0 -25
- ot/config/defaults/servers.yaml +0 -7
- ot/config/defaults/snippets.yaml +0 -4
- ot_tools/firecrawl.py +0 -732
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/WHEEL +0 -0
- {onetool_mcp-1.0.0b1.dist-info → onetool_mcp-1.0.0rc2.dist-info}/entry_points.txt +0 -0
- /ot/config/{defaults → global_templates}/tool_templates/extension.py +0 -0
- /ot/config/{defaults → global_templates}/tool_templates/isolated.py +0 -0
ot/logging/entry.py
CHANGED
|
@@ -1,213 +1,213 @@
|
|
|
1
|
-
"""LogEntry class for structured logging.
|
|
2
|
-
|
|
3
|
-
A simple struct for building log entries with automatic timing.
|
|
4
|
-
Supports fluent API, dict-style access, and lazy duration calculation.
|
|
5
|
-
|
|
6
|
-
Example:
|
|
7
|
-
# Inline - all fields in constructor
|
|
8
|
-
logger.debug(LogEntry(event="command.received", command=command))
|
|
9
|
-
|
|
10
|
-
# Fluent - chain adds
|
|
11
|
-
logger.debug(LogEntry(event="tool.lookup")
|
|
12
|
-
.add("function", func_name)
|
|
13
|
-
.add("found", True))
|
|
14
|
-
|
|
15
|
-
# Multiple logs show increasing duration (no caching)
|
|
16
|
-
entry = LogEntry(event="multi_step")
|
|
17
|
-
do_step_1()
|
|
18
|
-
logger.debug(entry) # duration: 0.1s
|
|
19
|
-
do_step_2()
|
|
20
|
-
logger.info(entry) # duration: 0.3s
|
|
21
|
-
"""
|
|
22
|
-
|
|
23
|
-
from __future__ import annotations
|
|
24
|
-
|
|
25
|
-
import json
|
|
26
|
-
import time
|
|
27
|
-
from typing import Any
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class LogEntry:
|
|
31
|
-
"""Structured log entry with automatic timing.
|
|
32
|
-
|
|
33
|
-
Timing starts automatically on creation. Duration is calculated
|
|
34
|
-
lazily in __str__ without caching, so multiple logs show increasing
|
|
35
|
-
duration.
|
|
36
|
-
"""
|
|
37
|
-
|
|
38
|
-
def __init__(self, **initial_fields: Any) -> None:
|
|
39
|
-
"""Initialize a log entry with optional initial fields.
|
|
40
|
-
|
|
41
|
-
Args:
|
|
42
|
-
**initial_fields: Initial fields for the log entry
|
|
43
|
-
"""
|
|
44
|
-
self._start_time = time.perf_counter()
|
|
45
|
-
self._fields: dict[str, Any] = dict(initial_fields)
|
|
46
|
-
self._status: str | None = None
|
|
47
|
-
self._status_code: int | None = None
|
|
48
|
-
self._error_type: str | None = None
|
|
49
|
-
self._error_message: str | None = None
|
|
50
|
-
|
|
51
|
-
def add(self, key: str | None = None, value: Any = None, **kwargs: Any) -> LogEntry:
|
|
52
|
-
"""Add one or more fields to the entry.
|
|
53
|
-
|
|
54
|
-
Can be called with a single key-value pair or with keyword arguments.
|
|
55
|
-
|
|
56
|
-
Args:
|
|
57
|
-
key: Field name (optional if using kwargs)
|
|
58
|
-
value: Field value (required if key is provided)
|
|
59
|
-
**kwargs: Bulk field additions
|
|
60
|
-
|
|
61
|
-
Returns:
|
|
62
|
-
Self for method chaining
|
|
63
|
-
|
|
64
|
-
Example:
|
|
65
|
-
entry.add("function", func_name)
|
|
66
|
-
entry.add(function=func_name, found=True)
|
|
67
|
-
"""
|
|
68
|
-
if key is not None:
|
|
69
|
-
self._fields[key] = value
|
|
70
|
-
self._fields.update(kwargs)
|
|
71
|
-
return self
|
|
72
|
-
|
|
73
|
-
def success(self, status_code: int | None = None) -> LogEntry:
|
|
74
|
-
"""Mark the entry as successful.
|
|
75
|
-
|
|
76
|
-
Args:
|
|
77
|
-
status_code: Optional HTTP status code
|
|
78
|
-
|
|
79
|
-
Returns:
|
|
80
|
-
Self for method chaining
|
|
81
|
-
"""
|
|
82
|
-
self._status = "SUCCESS"
|
|
83
|
-
self._status_code = status_code
|
|
84
|
-
return self
|
|
85
|
-
|
|
86
|
-
def failure(
|
|
87
|
-
self,
|
|
88
|
-
error: Exception | None = None,
|
|
89
|
-
error_type: str | None = None,
|
|
90
|
-
error_message: str | None = None,
|
|
91
|
-
) -> LogEntry:
|
|
92
|
-
"""Mark the entry as failed.
|
|
93
|
-
|
|
94
|
-
Args:
|
|
95
|
-
error: Exception that caused the failure
|
|
96
|
-
error_type: Type name of the error
|
|
97
|
-
error_message: Error message
|
|
98
|
-
|
|
99
|
-
Returns:
|
|
100
|
-
Self for method chaining
|
|
101
|
-
"""
|
|
102
|
-
self._status = "FAILED"
|
|
103
|
-
if error is not None:
|
|
104
|
-
self._error_type = type(error).__name__
|
|
105
|
-
self._error_message = str(error)
|
|
106
|
-
if error_type is not None:
|
|
107
|
-
self._error_type = error_type
|
|
108
|
-
if error_message is not None:
|
|
109
|
-
self._error_message = error_message
|
|
110
|
-
return self
|
|
111
|
-
|
|
112
|
-
def __setitem__(self, key: str, value: Any) -> None:
|
|
113
|
-
"""Set a field using dict-style access.
|
|
114
|
-
|
|
115
|
-
Args:
|
|
116
|
-
key: Field name
|
|
117
|
-
value: Field value
|
|
118
|
-
"""
|
|
119
|
-
self._fields[key] = value
|
|
120
|
-
|
|
121
|
-
def __getitem__(self, key: str) -> Any:
|
|
122
|
-
"""Get a field using dict-style access.
|
|
123
|
-
|
|
124
|
-
Args:
|
|
125
|
-
key: Field name
|
|
126
|
-
|
|
127
|
-
Returns:
|
|
128
|
-
Field value
|
|
129
|
-
|
|
130
|
-
Raises:
|
|
131
|
-
KeyError: If field doesn't exist
|
|
132
|
-
"""
|
|
133
|
-
return self._fields[key]
|
|
134
|
-
|
|
135
|
-
def __contains__(self, key: str) -> bool:
|
|
136
|
-
"""Check if a field exists.
|
|
137
|
-
|
|
138
|
-
Args:
|
|
139
|
-
key: Field name
|
|
140
|
-
|
|
141
|
-
Returns:
|
|
142
|
-
True if field exists
|
|
143
|
-
"""
|
|
144
|
-
return key in self._fields
|
|
145
|
-
|
|
146
|
-
@property
|
|
147
|
-
def fields(self) -> dict[str, Any]:
|
|
148
|
-
"""Return a copy of the fields for testing access.
|
|
149
|
-
|
|
150
|
-
Returns:
|
|
151
|
-
Copy of internal fields dictionary
|
|
152
|
-
"""
|
|
153
|
-
return dict(self._fields)
|
|
154
|
-
|
|
155
|
-
@property
|
|
156
|
-
def duration(self) -> float:
|
|
157
|
-
"""Return current duration since entry creation.
|
|
158
|
-
|
|
159
|
-
Returns:
|
|
160
|
-
Duration in seconds (not cached, calculated fresh each call)
|
|
161
|
-
"""
|
|
162
|
-
return round(time.perf_counter() - self._start_time, 3)
|
|
163
|
-
|
|
164
|
-
def to_dict(self) -> dict[str, Any]:
|
|
165
|
-
"""Return all fields with duration for output.
|
|
166
|
-
|
|
167
|
-
Returns:
|
|
168
|
-
Dict with all fields, duration, and status info
|
|
169
|
-
"""
|
|
170
|
-
output = dict(self._fields)
|
|
171
|
-
output["duration"] = self.duration
|
|
172
|
-
|
|
173
|
-
if self._status is not None:
|
|
174
|
-
output["status"] = self._status
|
|
175
|
-
if self._status_code is not None:
|
|
176
|
-
output["statusCode"] = self._status_code
|
|
177
|
-
if self._error_type is not None:
|
|
178
|
-
output["errorType"] = self._error_type
|
|
179
|
-
if self._error_message is not None:
|
|
180
|
-
output["errorMessage"] = self._error_message
|
|
181
|
-
|
|
182
|
-
return output
|
|
183
|
-
|
|
184
|
-
def __str__(self) -> str:
|
|
185
|
-
"""Serialize to JSON with duration.
|
|
186
|
-
|
|
187
|
-
Duration is calculated lazily (not cached) so multiple
|
|
188
|
-
calls show increasing duration.
|
|
189
|
-
|
|
190
|
-
Returns:
|
|
191
|
-
JSON string with fields and duration
|
|
192
|
-
"""
|
|
193
|
-
output = dict(self._fields)
|
|
194
|
-
output["duration"] = round(time.perf_counter() - self._start_time, 3)
|
|
195
|
-
|
|
196
|
-
if self._status is not None:
|
|
197
|
-
output["status"] = self._status
|
|
198
|
-
if self._status_code is not None:
|
|
199
|
-
output["statusCode"] = self._status_code
|
|
200
|
-
if self._error_type is not None:
|
|
201
|
-
output["errorType"] = self._error_type
|
|
202
|
-
if self._error_message is not None:
|
|
203
|
-
output["errorMessage"] = self._error_message
|
|
204
|
-
|
|
205
|
-
return json.dumps(output, separators=(",", ":"), default=str)
|
|
206
|
-
|
|
207
|
-
def __repr__(self) -> str:
|
|
208
|
-
"""Return a debug representation.
|
|
209
|
-
|
|
210
|
-
Returns:
|
|
211
|
-
String showing LogEntry fields
|
|
212
|
-
"""
|
|
213
|
-
return f"LogEntry({self._fields!r})"
|
|
1
|
+
"""LogEntry class for structured logging.
|
|
2
|
+
|
|
3
|
+
A simple struct for building log entries with automatic timing.
|
|
4
|
+
Supports fluent API, dict-style access, and lazy duration calculation.
|
|
5
|
+
|
|
6
|
+
Example:
|
|
7
|
+
# Inline - all fields in constructor
|
|
8
|
+
logger.debug(LogEntry(event="command.received", command=command))
|
|
9
|
+
|
|
10
|
+
# Fluent - chain adds
|
|
11
|
+
logger.debug(LogEntry(event="tool.lookup")
|
|
12
|
+
.add("function", func_name)
|
|
13
|
+
.add("found", True))
|
|
14
|
+
|
|
15
|
+
# Multiple logs show increasing duration (no caching)
|
|
16
|
+
entry = LogEntry(event="multi_step")
|
|
17
|
+
do_step_1()
|
|
18
|
+
logger.debug(entry) # duration: 0.1s
|
|
19
|
+
do_step_2()
|
|
20
|
+
logger.info(entry) # duration: 0.3s
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
from __future__ import annotations
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
import time
|
|
27
|
+
from typing import Any
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class LogEntry:
|
|
31
|
+
"""Structured log entry with automatic timing.
|
|
32
|
+
|
|
33
|
+
Timing starts automatically on creation. Duration is calculated
|
|
34
|
+
lazily in __str__ without caching, so multiple logs show increasing
|
|
35
|
+
duration.
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, **initial_fields: Any) -> None:
|
|
39
|
+
"""Initialize a log entry with optional initial fields.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
**initial_fields: Initial fields for the log entry
|
|
43
|
+
"""
|
|
44
|
+
self._start_time = time.perf_counter()
|
|
45
|
+
self._fields: dict[str, Any] = dict(initial_fields)
|
|
46
|
+
self._status: str | None = None
|
|
47
|
+
self._status_code: int | None = None
|
|
48
|
+
self._error_type: str | None = None
|
|
49
|
+
self._error_message: str | None = None
|
|
50
|
+
|
|
51
|
+
def add(self, key: str | None = None, value: Any = None, **kwargs: Any) -> LogEntry:
|
|
52
|
+
"""Add one or more fields to the entry.
|
|
53
|
+
|
|
54
|
+
Can be called with a single key-value pair or with keyword arguments.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
key: Field name (optional if using kwargs)
|
|
58
|
+
value: Field value (required if key is provided)
|
|
59
|
+
**kwargs: Bulk field additions
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
Self for method chaining
|
|
63
|
+
|
|
64
|
+
Example:
|
|
65
|
+
entry.add("function", func_name)
|
|
66
|
+
entry.add(function=func_name, found=True)
|
|
67
|
+
"""
|
|
68
|
+
if key is not None:
|
|
69
|
+
self._fields[key] = value
|
|
70
|
+
self._fields.update(kwargs)
|
|
71
|
+
return self
|
|
72
|
+
|
|
73
|
+
def success(self, status_code: int | None = None) -> LogEntry:
|
|
74
|
+
"""Mark the entry as successful.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
status_code: Optional HTTP status code
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
Self for method chaining
|
|
81
|
+
"""
|
|
82
|
+
self._status = "SUCCESS"
|
|
83
|
+
self._status_code = status_code
|
|
84
|
+
return self
|
|
85
|
+
|
|
86
|
+
def failure(
|
|
87
|
+
self,
|
|
88
|
+
error: Exception | None = None,
|
|
89
|
+
error_type: str | None = None,
|
|
90
|
+
error_message: str | None = None,
|
|
91
|
+
) -> LogEntry:
|
|
92
|
+
"""Mark the entry as failed.
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
error: Exception that caused the failure
|
|
96
|
+
error_type: Type name of the error
|
|
97
|
+
error_message: Error message
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Self for method chaining
|
|
101
|
+
"""
|
|
102
|
+
self._status = "FAILED"
|
|
103
|
+
if error is not None:
|
|
104
|
+
self._error_type = type(error).__name__
|
|
105
|
+
self._error_message = str(error)
|
|
106
|
+
if error_type is not None:
|
|
107
|
+
self._error_type = error_type
|
|
108
|
+
if error_message is not None:
|
|
109
|
+
self._error_message = error_message
|
|
110
|
+
return self
|
|
111
|
+
|
|
112
|
+
def __setitem__(self, key: str, value: Any) -> None:
|
|
113
|
+
"""Set a field using dict-style access.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
key: Field name
|
|
117
|
+
value: Field value
|
|
118
|
+
"""
|
|
119
|
+
self._fields[key] = value
|
|
120
|
+
|
|
121
|
+
def __getitem__(self, key: str) -> Any:
|
|
122
|
+
"""Get a field using dict-style access.
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
key: Field name
|
|
126
|
+
|
|
127
|
+
Returns:
|
|
128
|
+
Field value
|
|
129
|
+
|
|
130
|
+
Raises:
|
|
131
|
+
KeyError: If field doesn't exist
|
|
132
|
+
"""
|
|
133
|
+
return self._fields[key]
|
|
134
|
+
|
|
135
|
+
def __contains__(self, key: str) -> bool:
|
|
136
|
+
"""Check if a field exists.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
key: Field name
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
True if field exists
|
|
143
|
+
"""
|
|
144
|
+
return key in self._fields
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def fields(self) -> dict[str, Any]:
|
|
148
|
+
"""Return a copy of the fields for testing access.
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Copy of internal fields dictionary
|
|
152
|
+
"""
|
|
153
|
+
return dict(self._fields)
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def duration(self) -> float:
|
|
157
|
+
"""Return current duration since entry creation.
|
|
158
|
+
|
|
159
|
+
Returns:
|
|
160
|
+
Duration in seconds (not cached, calculated fresh each call)
|
|
161
|
+
"""
|
|
162
|
+
return round(time.perf_counter() - self._start_time, 3)
|
|
163
|
+
|
|
164
|
+
def to_dict(self) -> dict[str, Any]:
|
|
165
|
+
"""Return all fields with duration for output.
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
Dict with all fields, duration, and status info
|
|
169
|
+
"""
|
|
170
|
+
output = dict(self._fields)
|
|
171
|
+
output["duration"] = self.duration
|
|
172
|
+
|
|
173
|
+
if self._status is not None:
|
|
174
|
+
output["status"] = self._status
|
|
175
|
+
if self._status_code is not None:
|
|
176
|
+
output["statusCode"] = self._status_code
|
|
177
|
+
if self._error_type is not None:
|
|
178
|
+
output["errorType"] = self._error_type
|
|
179
|
+
if self._error_message is not None:
|
|
180
|
+
output["errorMessage"] = self._error_message
|
|
181
|
+
|
|
182
|
+
return output
|
|
183
|
+
|
|
184
|
+
def __str__(self) -> str:
|
|
185
|
+
"""Serialize to JSON with duration.
|
|
186
|
+
|
|
187
|
+
Duration is calculated lazily (not cached) so multiple
|
|
188
|
+
calls show increasing duration.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
JSON string with fields and duration
|
|
192
|
+
"""
|
|
193
|
+
output = dict(self._fields)
|
|
194
|
+
output["duration"] = round(time.perf_counter() - self._start_time, 3)
|
|
195
|
+
|
|
196
|
+
if self._status is not None:
|
|
197
|
+
output["status"] = self._status
|
|
198
|
+
if self._status_code is not None:
|
|
199
|
+
output["statusCode"] = self._status_code
|
|
200
|
+
if self._error_type is not None:
|
|
201
|
+
output["errorType"] = self._error_type
|
|
202
|
+
if self._error_message is not None:
|
|
203
|
+
output["errorMessage"] = self._error_message
|
|
204
|
+
|
|
205
|
+
return json.dumps(output, separators=(",", ":"), default=str)
|
|
206
|
+
|
|
207
|
+
def __repr__(self) -> str:
|
|
208
|
+
"""Return a debug representation.
|
|
209
|
+
|
|
210
|
+
Returns:
|
|
211
|
+
String showing LogEntry fields
|
|
212
|
+
"""
|
|
213
|
+
return f"LogEntry({self._fields!r})"
|