meshagent-tools 0.25.0__py3-none-any.whl → 0.25.1__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.
- meshagent/tools/__init__.py +23 -0
- meshagent/tools/container_shell.py +226 -0
- meshagent/tools/script.py +2 -4
- meshagent/tools/version.py +1 -1
- meshagent/tools/web_toolkit.py +111 -18
- {meshagent_tools-0.25.0.dist-info → meshagent_tools-0.25.1.dist-info}/METADATA +3 -2
- {meshagent_tools-0.25.0.dist-info → meshagent_tools-0.25.1.dist-info}/RECORD +10 -9
- {meshagent_tools-0.25.0.dist-info → meshagent_tools-0.25.1.dist-info}/WHEEL +0 -0
- {meshagent_tools-0.25.0.dist-info → meshagent_tools-0.25.1.dist-info}/licenses/LICENSE +0 -0
- {meshagent_tools-0.25.0.dist-info → meshagent_tools-0.25.1.dist-info}/top_level.txt +0 -0
meshagent/tools/__init__.py
CHANGED
|
@@ -31,6 +31,19 @@ from .hosting import (
|
|
|
31
31
|
)
|
|
32
32
|
from .multi_tool import MultiTool, MultiToolkit
|
|
33
33
|
from .version import __version__
|
|
34
|
+
from .web_toolkit import (
|
|
35
|
+
WebFetchConfig,
|
|
36
|
+
WebFetchTool,
|
|
37
|
+
WebFetchToolkitBuilder,
|
|
38
|
+
WebToolkit,
|
|
39
|
+
)
|
|
40
|
+
from .container_shell import (
|
|
41
|
+
ContainerShellToolConfig,
|
|
42
|
+
ContainerShellToolkitBuilder,
|
|
43
|
+
ContainerShellTool,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
from .script import ScriptTool, ScriptToolConfig, ScriptToolkitBuilder
|
|
34
47
|
|
|
35
48
|
from meshagent.api import websocket_protocol, RoomClient, ParticipantToken
|
|
36
49
|
from meshagent.api.websocket_protocol import WebSocketClientProtocol
|
|
@@ -66,5 +79,15 @@ __all__ = [
|
|
|
66
79
|
make_toolkits,
|
|
67
80
|
ToolkitConfig,
|
|
68
81
|
get_bytes_from_url,
|
|
82
|
+
WebFetchConfig,
|
|
83
|
+
WebFetchTool,
|
|
84
|
+
WebFetchToolkitBuilder,
|
|
85
|
+
WebToolkit,
|
|
86
|
+
ContainerShellToolConfig,
|
|
87
|
+
ContainerShellToolkitBuilder,
|
|
88
|
+
ContainerShellTool,
|
|
89
|
+
ScriptTool,
|
|
90
|
+
ScriptToolConfig,
|
|
91
|
+
ScriptToolkitBuilder,
|
|
69
92
|
__version__,
|
|
70
93
|
]
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
from meshagent.api import RoomClient
|
|
2
|
+
from .tool import ToolContext, Tool
|
|
3
|
+
from .toolkit import Toolkit, ToolkitBuilder
|
|
4
|
+
|
|
5
|
+
from meshagent.api.specs.service import ContainerMountSpec, RoomStorageMountSpec
|
|
6
|
+
from typing import Literal, Optional
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
import logging
|
|
10
|
+
import asyncio
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger("container_shell_tool")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
DEFAULT_CONTAINER_MOUNT_SPEC = ContainerMountSpec(
|
|
17
|
+
room=[RoomStorageMountSpec(path="/data")]
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ContainerShellToolConfig(BaseModel):
|
|
22
|
+
name: Literal["container_shell"] = "container_shell"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ContainerShellToolkitBuilder(ToolkitBuilder):
|
|
26
|
+
def __init__(
|
|
27
|
+
self,
|
|
28
|
+
*,
|
|
29
|
+
name: str = "container_shell",
|
|
30
|
+
working_directory: Optional[str] = None,
|
|
31
|
+
image: Optional[str] = "python:3.13",
|
|
32
|
+
mounts: Optional[ContainerMountSpec] = DEFAULT_CONTAINER_MOUNT_SPEC,
|
|
33
|
+
env: Optional[dict[str, str]] = None,
|
|
34
|
+
):
|
|
35
|
+
super().__init__(name=name, type=ContainerShellToolConfig)
|
|
36
|
+
|
|
37
|
+
self.working_directory = working_directory
|
|
38
|
+
self.image = image
|
|
39
|
+
self.mounts = mounts
|
|
40
|
+
self.env = env
|
|
41
|
+
|
|
42
|
+
async def make(
|
|
43
|
+
self, *, room: RoomClient, model: str, config: ContainerShellToolConfig
|
|
44
|
+
) -> Toolkit:
|
|
45
|
+
return Toolkit(
|
|
46
|
+
name=self.name,
|
|
47
|
+
tools=[
|
|
48
|
+
ContainerShellTool(
|
|
49
|
+
name=self.name,
|
|
50
|
+
working_directory=self.working_directory,
|
|
51
|
+
image=self.image,
|
|
52
|
+
mounts=self.mounts,
|
|
53
|
+
env=self.env,
|
|
54
|
+
)
|
|
55
|
+
],
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class ContainerShellTool(Tool):
|
|
60
|
+
def __init__(
|
|
61
|
+
self,
|
|
62
|
+
*,
|
|
63
|
+
name: str = "container_shell",
|
|
64
|
+
description: Optional[str] = None,
|
|
65
|
+
title: Optional[str] = None,
|
|
66
|
+
working_directory: Optional[str] = None,
|
|
67
|
+
image: Optional[str] = "python:3.13",
|
|
68
|
+
mounts: Optional[ContainerMountSpec] = DEFAULT_CONTAINER_MOUNT_SPEC,
|
|
69
|
+
env: Optional[dict[str, str]] = None,
|
|
70
|
+
):
|
|
71
|
+
self.working_directory = working_directory
|
|
72
|
+
self.image = image
|
|
73
|
+
self.mounts = mounts
|
|
74
|
+
self._container_id = None
|
|
75
|
+
self.env = env
|
|
76
|
+
|
|
77
|
+
super().__init__(
|
|
78
|
+
name=name,
|
|
79
|
+
description=description
|
|
80
|
+
or "execute shell commands in a container and return the result",
|
|
81
|
+
title=title,
|
|
82
|
+
input_schema={
|
|
83
|
+
"type": "object",
|
|
84
|
+
"required": ["commands"],
|
|
85
|
+
"additionalProperties": False,
|
|
86
|
+
"properties": {
|
|
87
|
+
"commands": {"type": "array", "items": {"type": "string"}},
|
|
88
|
+
"max_output_length": {"type": "integer"},
|
|
89
|
+
"timeout_ms": {"type": "integer"},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
async def execute(
|
|
95
|
+
self,
|
|
96
|
+
context: ToolContext,
|
|
97
|
+
**kwargs,
|
|
98
|
+
):
|
|
99
|
+
commands = kwargs.get("commands") or []
|
|
100
|
+
max_output_length = kwargs.get("max_output_length")
|
|
101
|
+
timeout_ms = kwargs.get("timeout_ms")
|
|
102
|
+
|
|
103
|
+
if not commands:
|
|
104
|
+
raise Exception("commands is required")
|
|
105
|
+
|
|
106
|
+
if self.image is None:
|
|
107
|
+
raise Exception("container_shell requires an image")
|
|
108
|
+
|
|
109
|
+
results = []
|
|
110
|
+
encoding = os.device_encoding(1) or "utf-8"
|
|
111
|
+
|
|
112
|
+
left = max_output_length
|
|
113
|
+
|
|
114
|
+
def limit(s: str):
|
|
115
|
+
nonlocal left
|
|
116
|
+
if left is not None:
|
|
117
|
+
s = s[0:left]
|
|
118
|
+
left -= len(s)
|
|
119
|
+
return s
|
|
120
|
+
else:
|
|
121
|
+
return s
|
|
122
|
+
|
|
123
|
+
timeout = float(timeout_ms) / 1000.0 if timeout_ms else 20 * 1000.0
|
|
124
|
+
|
|
125
|
+
running = False
|
|
126
|
+
|
|
127
|
+
if self._container_id:
|
|
128
|
+
for c in await context.room.containers.list():
|
|
129
|
+
if c.id == self._container_id:
|
|
130
|
+
running = True
|
|
131
|
+
|
|
132
|
+
if not running:
|
|
133
|
+
self._container_id = await context.room.containers.run(
|
|
134
|
+
command="sleep infinity",
|
|
135
|
+
image=self.image,
|
|
136
|
+
mounts=self.mounts,
|
|
137
|
+
writable_root_fs=True,
|
|
138
|
+
env=self.env,
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
container_id = self._container_id
|
|
142
|
+
|
|
143
|
+
try:
|
|
144
|
+
logger.info(
|
|
145
|
+
"executing shell commands in container %s with timeout %s: %s",
|
|
146
|
+
container_id,
|
|
147
|
+
timeout,
|
|
148
|
+
commands,
|
|
149
|
+
)
|
|
150
|
+
import shlex
|
|
151
|
+
|
|
152
|
+
for command in commands:
|
|
153
|
+
command_to_run = command
|
|
154
|
+
if self.working_directory:
|
|
155
|
+
command_to_run = (
|
|
156
|
+
f"cd {shlex.quote(self.working_directory)} && {command}"
|
|
157
|
+
)
|
|
158
|
+
exec = await context.room.containers.exec(
|
|
159
|
+
container_id=container_id,
|
|
160
|
+
command=shlex.join(["bash", "-lc", command_to_run]),
|
|
161
|
+
tty=False,
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
stdout = bytearray()
|
|
165
|
+
stderr = bytearray()
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
async with asyncio.timeout(timeout):
|
|
169
|
+
async for se in exec.stderr():
|
|
170
|
+
stderr.extend(se)
|
|
171
|
+
|
|
172
|
+
async for so in exec.stdout():
|
|
173
|
+
stdout.extend(so)
|
|
174
|
+
|
|
175
|
+
exit_code = await exec.result
|
|
176
|
+
|
|
177
|
+
results.append(
|
|
178
|
+
{
|
|
179
|
+
"outcome": {
|
|
180
|
+
"type": "exit",
|
|
181
|
+
"exit_code": exit_code,
|
|
182
|
+
},
|
|
183
|
+
"stdout": stdout.decode(),
|
|
184
|
+
"stderr": stderr.decode(),
|
|
185
|
+
}
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
except asyncio.TimeoutError:
|
|
189
|
+
logger.info("The command timed out after %ss", timeout)
|
|
190
|
+
await exec.kill()
|
|
191
|
+
|
|
192
|
+
results.append(
|
|
193
|
+
{
|
|
194
|
+
"outcome": {"type": "timeout"},
|
|
195
|
+
"stdout": limit(stdout.decode(encoding, errors="replace")),
|
|
196
|
+
"stderr": limit(stderr.decode(encoding, errors="replace")),
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
break
|
|
200
|
+
|
|
201
|
+
except Exception as ex:
|
|
202
|
+
results.append(
|
|
203
|
+
{
|
|
204
|
+
"outcome": {
|
|
205
|
+
"type": "exit",
|
|
206
|
+
"exit_code": 1,
|
|
207
|
+
},
|
|
208
|
+
"stdout": "",
|
|
209
|
+
"stderr": f"{ex}",
|
|
210
|
+
}
|
|
211
|
+
)
|
|
212
|
+
break
|
|
213
|
+
|
|
214
|
+
except Exception as ex:
|
|
215
|
+
results.append(
|
|
216
|
+
{
|
|
217
|
+
"outcome": {
|
|
218
|
+
"type": "exit",
|
|
219
|
+
"exit_code": 1,
|
|
220
|
+
},
|
|
221
|
+
"stdout": "",
|
|
222
|
+
"stderr": f"{ex}",
|
|
223
|
+
}
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return {"results": results}
|
meshagent/tools/script.py
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
from meshagent.api import RoomClient
|
|
2
|
-
from meshagent.tools import
|
|
2
|
+
from meshagent.tools.tool import Tool, ToolContext
|
|
3
|
+
from meshagent.tools.toolkit import Toolkit, ToolkitBuilder
|
|
3
4
|
|
|
4
|
-
from meshagent.agents.adapter import (
|
|
5
|
-
ToolkitBuilder,
|
|
6
|
-
)
|
|
7
5
|
|
|
8
6
|
from meshagent.api.specs.service import ContainerMountSpec, RoomStorageMountSpec
|
|
9
7
|
from typing import Literal
|
meshagent/tools/version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.25.
|
|
1
|
+
__version__ = "0.25.1"
|
meshagent/tools/web_toolkit.py
CHANGED
|
@@ -1,19 +1,29 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import mimetypes
|
|
5
|
+
import os
|
|
6
|
+
from urllib.parse import urlparse
|
|
7
|
+
|
|
8
|
+
from meshagent.api.http import new_client_session
|
|
9
|
+
from meshagent.api.messaging import FileResponse, JsonResponse, Response, TextResponse
|
|
10
|
+
from meshagent.tools.config import ToolkitConfig
|
|
11
|
+
from meshagent.tools.tool import Tool, ToolContext
|
|
12
|
+
from meshagent.tools.toolkit import Toolkit, ToolkitBuilder
|
|
13
|
+
from meshagent.api.room_server_client import RoomClient
|
|
4
14
|
|
|
5
15
|
|
|
6
16
|
class WebToolkit(Toolkit):
|
|
7
17
|
def __init__(self):
|
|
8
|
-
super().__init__(tools=[WebFetchTool()])
|
|
18
|
+
super().__init__(name="web_fetch", tools=[WebFetchTool()])
|
|
9
19
|
|
|
10
20
|
|
|
11
21
|
class WebFetchTool(Tool):
|
|
12
22
|
def __init__(self):
|
|
13
23
|
super().__init__(
|
|
14
|
-
name="
|
|
15
|
-
title="
|
|
16
|
-
description="
|
|
24
|
+
name="web_fetch",
|
|
25
|
+
title="web fetch",
|
|
26
|
+
description="fetches a url and returns text, json, or file content",
|
|
17
27
|
input_schema={
|
|
18
28
|
"type": "object",
|
|
19
29
|
"properties": {
|
|
@@ -22,21 +32,104 @@ class WebFetchTool(Tool):
|
|
|
22
32
|
"description": "the url of the web page (always start it with a proper scheme like https://)",
|
|
23
33
|
}
|
|
24
34
|
},
|
|
35
|
+
"required": ["url"],
|
|
25
36
|
"additionalProperties": False,
|
|
26
37
|
},
|
|
27
38
|
)
|
|
28
39
|
|
|
29
|
-
async def execute(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
) -> str:
|
|
35
|
-
async with ClientSession() as session:
|
|
40
|
+
async def execute(self, context: ToolContext, **kwargs: object) -> Response:
|
|
41
|
+
url = str(kwargs.get("url", ""))
|
|
42
|
+
if not url:
|
|
43
|
+
raise ValueError("url is required")
|
|
44
|
+
async with new_client_session() as session:
|
|
36
45
|
async with session.get(url) as resp:
|
|
37
|
-
|
|
46
|
+
if resp.status >= 400:
|
|
47
|
+
raise Exception(f"web fetch failed with status {resp.status}")
|
|
48
|
+
|
|
49
|
+
content_type = (resp.content_type or "").lower()
|
|
50
|
+
data = await resp.read()
|
|
51
|
+
|
|
52
|
+
if _is_json_content_type(content_type):
|
|
53
|
+
text = _decode_text(data=data, charset=resp.charset)
|
|
54
|
+
try:
|
|
55
|
+
parsed = json.loads(text)
|
|
56
|
+
except json.JSONDecodeError:
|
|
57
|
+
return TextResponse(text=text)
|
|
58
|
+
|
|
59
|
+
if isinstance(parsed, dict):
|
|
60
|
+
return JsonResponse(json=parsed)
|
|
61
|
+
return JsonResponse(json={"data": parsed})
|
|
62
|
+
|
|
63
|
+
if _is_text_content_type(content_type):
|
|
64
|
+
text = _decode_text(data=data, charset=resp.charset)
|
|
65
|
+
if content_type == "text/html":
|
|
66
|
+
from html_to_markdown import convert
|
|
67
|
+
|
|
68
|
+
text = convert(text)
|
|
69
|
+
return TextResponse(text=text)
|
|
70
|
+
|
|
71
|
+
if _is_file_content_type(content_type):
|
|
72
|
+
filename = _infer_filename(url=url, content_type=content_type)
|
|
73
|
+
return FileResponse(
|
|
74
|
+
name=filename,
|
|
75
|
+
mime_type=content_type or "application/octet-stream",
|
|
76
|
+
data=data,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
filename = _infer_filename(url=url, content_type=content_type)
|
|
80
|
+
return FileResponse(
|
|
81
|
+
name=filename,
|
|
82
|
+
mime_type=content_type or "application/octet-stream",
|
|
83
|
+
data=data,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _decode_text(*, data: bytes, charset: str | None) -> str:
|
|
88
|
+
encoding = charset or "utf-8"
|
|
89
|
+
return data.decode(encoding, errors="replace")
|
|
90
|
+
|
|
38
91
|
|
|
39
|
-
|
|
92
|
+
def _is_json_content_type(content_type: str) -> bool:
|
|
93
|
+
if content_type in {"application/json", "text/json"}:
|
|
94
|
+
return True
|
|
95
|
+
return content_type.endswith("+json")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _is_text_content_type(content_type: str) -> bool:
|
|
99
|
+
if content_type.startswith("text/"):
|
|
100
|
+
return True
|
|
101
|
+
return content_type in {
|
|
102
|
+
"application/xml",
|
|
103
|
+
"application/xhtml+xml",
|
|
104
|
+
"application/javascript",
|
|
105
|
+
"application/x-javascript",
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _is_file_content_type(content_type: str) -> bool:
|
|
110
|
+
if content_type.startswith("image/"):
|
|
111
|
+
return True
|
|
112
|
+
return content_type == "application/pdf"
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _infer_filename(*, url: str, content_type: str) -> str:
|
|
116
|
+
parsed = urlparse(url)
|
|
117
|
+
basename = os.path.basename(parsed.path)
|
|
118
|
+
if basename:
|
|
119
|
+
return basename
|
|
120
|
+
extension = mimetypes.guess_extension(content_type or "") or ""
|
|
121
|
+
return f"downloaded-content{extension}"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class WebFetchConfig(ToolkitConfig):
|
|
125
|
+
name: str = "web_fetch"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class WebFetchToolkitBuilder(ToolkitBuilder):
|
|
129
|
+
def __init__(self):
|
|
130
|
+
super().__init__(name="web_fetch", type=WebFetchConfig)
|
|
40
131
|
|
|
41
|
-
|
|
42
|
-
|
|
132
|
+
async def make(
|
|
133
|
+
self, *, room: RoomClient, model: str, config: WebFetchConfig
|
|
134
|
+
) -> Toolkit:
|
|
135
|
+
return WebToolkit()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshagent-tools
|
|
3
|
-
Version: 0.25.
|
|
3
|
+
Version: 0.25.1
|
|
4
4
|
Summary: Tools for Meshagent
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Project-URL: Documentation, https://docs.meshagent.com
|
|
@@ -12,7 +12,8 @@ License-File: LICENSE
|
|
|
12
12
|
Requires-Dist: pyjwt~=2.10
|
|
13
13
|
Requires-Dist: pytest~=8.4
|
|
14
14
|
Requires-Dist: pytest-asyncio~=0.26
|
|
15
|
-
Requires-Dist: meshagent-api~=0.25.
|
|
15
|
+
Requires-Dist: meshagent-api~=0.25.1
|
|
16
|
+
Requires-Dist: html-to-markdown~=2.24.3
|
|
16
17
|
Requires-Dist: aiohttp[speedups]~=3.13.0
|
|
17
18
|
Requires-Dist: opentelemetry-distro~=0.54b1
|
|
18
19
|
Dynamic: license-file
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
meshagent/tools/__init__.py,sha256=
|
|
1
|
+
meshagent/tools/__init__.py,sha256=2qAAi4eUVq4q6gXyAGnjQze2Rs9Q9kIJfdm4oEheRPQ,1843
|
|
2
2
|
meshagent/tools/blob.py,sha256=Liw1zdtDc-Viy6Hcgrb4XZ8ULUPEubzShWAdIci0wWI,1505
|
|
3
3
|
meshagent/tools/config.py,sha256=zH2xGxg28K7Tg-aYor6LXdzf0LRxS9iE0679H1FuWhE,79
|
|
4
|
+
meshagent/tools/container_shell.py,sha256=BMcTi_j0-yUPk9ZkVux1j8CxDFmyrCYFn-XeT3S77Ik,7056
|
|
4
5
|
meshagent/tools/database.py,sha256=HWH7_Fm_8GexDJv_T-D6o0yJVUPmE-j31TU2AfcgaPs,18438
|
|
5
6
|
meshagent/tools/datetime.py,sha256=2pOUOWopYIsc5y4EoFo_1PdBaBcTSkeOOs_EqdqYTk0,17503
|
|
6
7
|
meshagent/tools/discovery.py,sha256=f7DJtwIiBQCxByTepsvGM2NRn-9KGxZTZMoTRCKYQ7E,1251
|
|
@@ -8,17 +9,17 @@ meshagent/tools/document_tools.py,sha256=LMULXOSBjsvhKjqzxUxe8586t0Vol0v1Btu5v6o
|
|
|
8
9
|
meshagent/tools/hosting.py,sha256=l1BCgnSrCJQsWU9Kycq3hEI4ZlYxffDfde6QeJUfko0,10678
|
|
9
10
|
meshagent/tools/multi_tool.py,sha256=hmWZO18Y2tuFG_7rvUed9er29aXleAC-r3YpXBCZWUY,4040
|
|
10
11
|
meshagent/tools/pydantic.py,sha256=n-MD0gC-oRtHSTUDD5IV2dP-xIk-zjcDgHfgjqMgiqM,1161
|
|
11
|
-
meshagent/tools/script.py,sha256=
|
|
12
|
+
meshagent/tools/script.py,sha256=eyQiufoc2ZkTUBTO58VQURnkkQA2lboED5s0-BvAvgM,11811
|
|
12
13
|
meshagent/tools/storage.py,sha256=NVpi9CZKSZUh8PTxxCdJhJy7Gzmdp55-zo2yHYGod_E,23340
|
|
13
14
|
meshagent/tools/strict_schema.py,sha256=IytdAANa6lsfrsg5FsJuqYrxH9D_fayl-Lc9EwgLJSM,6277
|
|
14
15
|
meshagent/tools/tool.py,sha256=HgvlOlz2wMrmD5aaV49fRpnGyXJwnVcH9j4wKaaPbWo,5935
|
|
15
16
|
meshagent/tools/toolkit.py,sha256=iVcCvhwWqmahDow9FN-VRWGo9MEj669Vw7TAB7Mx9Ww,4066
|
|
16
17
|
meshagent/tools/uuid.py,sha256=mzRwDmXy39U5lHhd9wqV4r-ZdS8jPfDTTs4UfW4KHJQ,1342
|
|
17
|
-
meshagent/tools/version.py,sha256=
|
|
18
|
-
meshagent/tools/web_toolkit.py,sha256=
|
|
18
|
+
meshagent/tools/version.py,sha256=ACu2Z3Q3TFgYpAno_eu9ssJ1QULjNXvjGvyqDSHrQ_o,23
|
|
19
|
+
meshagent/tools/web_toolkit.py,sha256=Seju8gpdUoPku7Yfar_s-cVOnlweFzKj-bFqrQVup8o,4603
|
|
19
20
|
meshagent/tools/tests/tool_decorator_test.py,sha256=Fd4uvoefU8hpdSWaiYen15tqnlwoY092G6hjYafaMGE,1190
|
|
20
|
-
meshagent_tools-0.25.
|
|
21
|
-
meshagent_tools-0.25.
|
|
22
|
-
meshagent_tools-0.25.
|
|
23
|
-
meshagent_tools-0.25.
|
|
24
|
-
meshagent_tools-0.25.
|
|
21
|
+
meshagent_tools-0.25.1.dist-info/licenses/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
|
|
22
|
+
meshagent_tools-0.25.1.dist-info/METADATA,sha256=I_DrA3zW7uRwNXwllW8OSipjUKQimC_BgOP4_8xoDBI,2930
|
|
23
|
+
meshagent_tools-0.25.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
24
|
+
meshagent_tools-0.25.1.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
|
|
25
|
+
meshagent_tools-0.25.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|