mail-swarms 1.3.2__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.
- mail/__init__.py +35 -0
- mail/api.py +1964 -0
- mail/cli.py +432 -0
- mail/client.py +1657 -0
- mail/config/__init__.py +8 -0
- mail/config/client.py +87 -0
- mail/config/server.py +165 -0
- mail/core/__init__.py +72 -0
- mail/core/actions.py +69 -0
- mail/core/agents.py +73 -0
- mail/core/message.py +366 -0
- mail/core/runtime.py +3537 -0
- mail/core/tasks.py +311 -0
- mail/core/tools.py +1206 -0
- mail/db/__init__.py +0 -0
- mail/db/init.py +182 -0
- mail/db/types.py +65 -0
- mail/db/utils.py +523 -0
- mail/examples/__init__.py +27 -0
- mail/examples/analyst_dummy/__init__.py +15 -0
- mail/examples/analyst_dummy/agent.py +136 -0
- mail/examples/analyst_dummy/prompts.py +44 -0
- mail/examples/consultant_dummy/__init__.py +15 -0
- mail/examples/consultant_dummy/agent.py +136 -0
- mail/examples/consultant_dummy/prompts.py +42 -0
- mail/examples/data_analysis/__init__.py +40 -0
- mail/examples/data_analysis/analyst/__init__.py +9 -0
- mail/examples/data_analysis/analyst/agent.py +67 -0
- mail/examples/data_analysis/analyst/prompts.py +53 -0
- mail/examples/data_analysis/processor/__init__.py +13 -0
- mail/examples/data_analysis/processor/actions.py +293 -0
- mail/examples/data_analysis/processor/agent.py +67 -0
- mail/examples/data_analysis/processor/prompts.py +48 -0
- mail/examples/data_analysis/reporter/__init__.py +10 -0
- mail/examples/data_analysis/reporter/actions.py +187 -0
- mail/examples/data_analysis/reporter/agent.py +67 -0
- mail/examples/data_analysis/reporter/prompts.py +49 -0
- mail/examples/data_analysis/statistics/__init__.py +18 -0
- mail/examples/data_analysis/statistics/actions.py +343 -0
- mail/examples/data_analysis/statistics/agent.py +67 -0
- mail/examples/data_analysis/statistics/prompts.py +60 -0
- mail/examples/mafia/__init__.py +0 -0
- mail/examples/mafia/game.py +1537 -0
- mail/examples/mafia/narrator_tools.py +396 -0
- mail/examples/mafia/personas.py +240 -0
- mail/examples/mafia/prompts.py +489 -0
- mail/examples/mafia/roles.py +147 -0
- mail/examples/mafia/spec.md +350 -0
- mail/examples/math_dummy/__init__.py +23 -0
- mail/examples/math_dummy/actions.py +252 -0
- mail/examples/math_dummy/agent.py +136 -0
- mail/examples/math_dummy/prompts.py +46 -0
- mail/examples/math_dummy/types.py +5 -0
- mail/examples/research/__init__.py +39 -0
- mail/examples/research/researcher/__init__.py +9 -0
- mail/examples/research/researcher/agent.py +67 -0
- mail/examples/research/researcher/prompts.py +54 -0
- mail/examples/research/searcher/__init__.py +10 -0
- mail/examples/research/searcher/actions.py +324 -0
- mail/examples/research/searcher/agent.py +67 -0
- mail/examples/research/searcher/prompts.py +53 -0
- mail/examples/research/summarizer/__init__.py +18 -0
- mail/examples/research/summarizer/actions.py +255 -0
- mail/examples/research/summarizer/agent.py +67 -0
- mail/examples/research/summarizer/prompts.py +55 -0
- mail/examples/research/verifier/__init__.py +10 -0
- mail/examples/research/verifier/actions.py +337 -0
- mail/examples/research/verifier/agent.py +67 -0
- mail/examples/research/verifier/prompts.py +52 -0
- mail/examples/supervisor/__init__.py +11 -0
- mail/examples/supervisor/agent.py +4 -0
- mail/examples/supervisor/prompts.py +93 -0
- mail/examples/support/__init__.py +33 -0
- mail/examples/support/classifier/__init__.py +10 -0
- mail/examples/support/classifier/actions.py +307 -0
- mail/examples/support/classifier/agent.py +68 -0
- mail/examples/support/classifier/prompts.py +56 -0
- mail/examples/support/coordinator/__init__.py +9 -0
- mail/examples/support/coordinator/agent.py +67 -0
- mail/examples/support/coordinator/prompts.py +48 -0
- mail/examples/support/faq/__init__.py +10 -0
- mail/examples/support/faq/actions.py +182 -0
- mail/examples/support/faq/agent.py +67 -0
- mail/examples/support/faq/prompts.py +42 -0
- mail/examples/support/sentiment/__init__.py +15 -0
- mail/examples/support/sentiment/actions.py +341 -0
- mail/examples/support/sentiment/agent.py +67 -0
- mail/examples/support/sentiment/prompts.py +54 -0
- mail/examples/weather_dummy/__init__.py +23 -0
- mail/examples/weather_dummy/actions.py +75 -0
- mail/examples/weather_dummy/agent.py +136 -0
- mail/examples/weather_dummy/prompts.py +35 -0
- mail/examples/weather_dummy/types.py +5 -0
- mail/factories/__init__.py +27 -0
- mail/factories/action.py +223 -0
- mail/factories/base.py +1531 -0
- mail/factories/supervisor.py +241 -0
- mail/net/__init__.py +7 -0
- mail/net/registry.py +712 -0
- mail/net/router.py +728 -0
- mail/net/server_utils.py +114 -0
- mail/net/types.py +247 -0
- mail/server.py +1605 -0
- mail/stdlib/__init__.py +0 -0
- mail/stdlib/anthropic/__init__.py +0 -0
- mail/stdlib/fs/__init__.py +15 -0
- mail/stdlib/fs/actions.py +209 -0
- mail/stdlib/http/__init__.py +19 -0
- mail/stdlib/http/actions.py +333 -0
- mail/stdlib/interswarm/__init__.py +11 -0
- mail/stdlib/interswarm/actions.py +208 -0
- mail/stdlib/mcp/__init__.py +19 -0
- mail/stdlib/mcp/actions.py +294 -0
- mail/stdlib/openai/__init__.py +13 -0
- mail/stdlib/openai/agents.py +451 -0
- mail/summarizer.py +234 -0
- mail/swarms_json/__init__.py +27 -0
- mail/swarms_json/types.py +87 -0
- mail/swarms_json/utils.py +255 -0
- mail/url_scheme.py +51 -0
- mail/utils/__init__.py +53 -0
- mail/utils/auth.py +194 -0
- mail/utils/context.py +17 -0
- mail/utils/logger.py +73 -0
- mail/utils/openai.py +212 -0
- mail/utils/parsing.py +89 -0
- mail/utils/serialize.py +292 -0
- mail/utils/store.py +49 -0
- mail/utils/string_builder.py +119 -0
- mail/utils/version.py +20 -0
- mail_swarms-1.3.2.dist-info/METADATA +237 -0
- mail_swarms-1.3.2.dist-info/RECORD +137 -0
- mail_swarms-1.3.2.dist-info/WHEEL +4 -0
- mail_swarms-1.3.2.dist-info/entry_points.txt +2 -0
- mail_swarms-1.3.2.dist-info/licenses/LICENSE +202 -0
- mail_swarms-1.3.2.dist-info/licenses/NOTICE +10 -0
- mail_swarms-1.3.2.dist-info/licenses/THIRD_PARTY_NOTICES.md +12334 -0
mail/cli.py
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Addison Kline
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import asyncio
|
|
6
|
+
import os
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
from mail import utils
|
|
12
|
+
from mail.client import MAILClientCLI
|
|
13
|
+
from mail.config import ClientConfig, ServerConfig
|
|
14
|
+
from mail.server import run_server
|
|
15
|
+
from mail.url_scheme import parse_swarm_url
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _str_to_bool(value: str | bool) -> bool:
|
|
19
|
+
"""
|
|
20
|
+
Parse common string representations of booleans.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
if isinstance(value, bool):
|
|
24
|
+
return value
|
|
25
|
+
|
|
26
|
+
normalized = value.lower()
|
|
27
|
+
if normalized in {"true", "t", "1", "yes", "y"}:
|
|
28
|
+
return True
|
|
29
|
+
if normalized in {"false", "f", "0", "no", "n"}:
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
raise argparse.ArgumentTypeError(
|
|
33
|
+
f"invalid boolean value '{value}'; expected true/false"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _run_server_with_args(args: argparse.Namespace) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Run a MAIL server with the given CLI args.
|
|
40
|
+
Given CLI args will override the defaults in the config file.
|
|
41
|
+
"""
|
|
42
|
+
original_config_path = os.environ.get("MAIL_CONFIG_PATH")
|
|
43
|
+
env_overridden = False
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
if args.config:
|
|
47
|
+
resolved_config = Path(args.config).expanduser().resolve()
|
|
48
|
+
os.environ["MAIL_CONFIG_PATH"] = str(resolved_config)
|
|
49
|
+
env_overridden = True
|
|
50
|
+
|
|
51
|
+
base_config = ServerConfig()
|
|
52
|
+
|
|
53
|
+
server_overrides: dict[str, object] = {}
|
|
54
|
+
if args.host is not None:
|
|
55
|
+
server_overrides["host"] = args.host
|
|
56
|
+
if args.port is not None:
|
|
57
|
+
server_overrides["port"] = args.port
|
|
58
|
+
if args.reload is not None:
|
|
59
|
+
server_overrides["reload"] = args.reload
|
|
60
|
+
if args.debug is not None:
|
|
61
|
+
server_overrides["debug"] = args.debug
|
|
62
|
+
|
|
63
|
+
swarm_overrides: dict[str, object] = {}
|
|
64
|
+
if args.swarm_name is not None:
|
|
65
|
+
swarm_overrides["name"] = args.swarm_name
|
|
66
|
+
if args.swarm_source is not None:
|
|
67
|
+
swarm_overrides["source"] = args.swarm_source
|
|
68
|
+
if args.swarm_registry is not None:
|
|
69
|
+
swarm_overrides["registry_file"] = args.swarm_registry
|
|
70
|
+
|
|
71
|
+
if swarm_overrides:
|
|
72
|
+
server_overrides["swarm"] = base_config.swarm.model_copy(
|
|
73
|
+
update=swarm_overrides
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
effective_config = (
|
|
77
|
+
base_config.model_copy(update=server_overrides)
|
|
78
|
+
if server_overrides
|
|
79
|
+
else base_config
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
run_server(cfg=effective_config)
|
|
83
|
+
finally:
|
|
84
|
+
if env_overridden:
|
|
85
|
+
if original_config_path is None:
|
|
86
|
+
os.environ.pop("MAIL_CONFIG_PATH", None)
|
|
87
|
+
else:
|
|
88
|
+
os.environ["MAIL_CONFIG_PATH"] = original_config_path
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _run_client_with_args(args: argparse.Namespace) -> None:
|
|
92
|
+
"""
|
|
93
|
+
Run a MAIL client with the given CLI args.
|
|
94
|
+
"""
|
|
95
|
+
# Parse swarm:// URLs if provided
|
|
96
|
+
swarm_url = parse_swarm_url(args.url)
|
|
97
|
+
if swarm_url:
|
|
98
|
+
if not swarm_url.server:
|
|
99
|
+
print("Error: swarm:// URL must include a 'server' parameter")
|
|
100
|
+
return
|
|
101
|
+
args.url = f"https://{swarm_url.server}"
|
|
102
|
+
if swarm_url.token and not args.api_key:
|
|
103
|
+
args.api_key = swarm_url.token
|
|
104
|
+
|
|
105
|
+
original_config_path = os.environ.get("MAIL_CONFIG_PATH")
|
|
106
|
+
env_overridden = False
|
|
107
|
+
|
|
108
|
+
try:
|
|
109
|
+
if args.config:
|
|
110
|
+
resolved_config = Path(args.config).expanduser().resolve()
|
|
111
|
+
os.environ["MAIL_CONFIG_PATH"] = str(resolved_config)
|
|
112
|
+
env_overridden = True
|
|
113
|
+
|
|
114
|
+
client_config = ClientConfig()
|
|
115
|
+
if args.timeout is not None:
|
|
116
|
+
client_config.timeout = args.timeout
|
|
117
|
+
|
|
118
|
+
if args.verbose:
|
|
119
|
+
client_config.verbose = True
|
|
120
|
+
|
|
121
|
+
client_cli = MAILClientCLI(args, config=client_config)
|
|
122
|
+
asyncio.run(client_cli.run())
|
|
123
|
+
finally:
|
|
124
|
+
if env_overridden:
|
|
125
|
+
if original_config_path is None:
|
|
126
|
+
os.environ.pop("MAIL_CONFIG_PATH", None)
|
|
127
|
+
else:
|
|
128
|
+
os.environ["MAIL_CONFIG_PATH"] = original_config_path
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _print_version(_args: argparse.Namespace) -> None:
|
|
132
|
+
"""
|
|
133
|
+
Print the version of MAIL.
|
|
134
|
+
"""
|
|
135
|
+
print(f"MAIL reference implementation version: {utils.get_version()}")
|
|
136
|
+
print(f"MAIL protocol version: {utils.get_protocol_version()}")
|
|
137
|
+
print(
|
|
138
|
+
"For a given MAIL reference implementation with version `x.y.z`, the protocol version is `x.y`"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _run_db_init(_args: argparse.Namespace) -> None:
|
|
143
|
+
"""
|
|
144
|
+
Initialize the database tables for MAIL.
|
|
145
|
+
"""
|
|
146
|
+
from mail.db.init import create_tables
|
|
147
|
+
|
|
148
|
+
asyncio.run(create_tables())
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _register_url_handler(_args: argparse.Namespace) -> None:
|
|
152
|
+
"""
|
|
153
|
+
Register the MAIL client as the OS handler for swarm:// URLs.
|
|
154
|
+
"""
|
|
155
|
+
platform = sys.platform
|
|
156
|
+
|
|
157
|
+
if platform == "linux":
|
|
158
|
+
_register_linux()
|
|
159
|
+
elif platform == "darwin":
|
|
160
|
+
_register_macos()
|
|
161
|
+
elif platform.startswith("win"):
|
|
162
|
+
_register_windows()
|
|
163
|
+
else:
|
|
164
|
+
print(f"Unsupported platform: {platform}")
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _register_linux() -> None:
|
|
168
|
+
"""
|
|
169
|
+
Register `swarm://` URL handler on Linux using XDG.
|
|
170
|
+
"""
|
|
171
|
+
desktop_entry = """[Desktop Entry]
|
|
172
|
+
Name=MAIL Client
|
|
173
|
+
Comment=Connect to MAIL servers via swarm:// URLs
|
|
174
|
+
Exec=mail client %u
|
|
175
|
+
Type=Application
|
|
176
|
+
MimeType=x-scheme-handler/swarm;
|
|
177
|
+
Terminal=true
|
|
178
|
+
NoDisplay=true
|
|
179
|
+
"""
|
|
180
|
+
applications_dir = Path.home() / ".local" / "share" / "applications"
|
|
181
|
+
applications_dir.mkdir(parents=True, exist_ok=True)
|
|
182
|
+
|
|
183
|
+
desktop_file = applications_dir / "mail-swarm.desktop"
|
|
184
|
+
desktop_file.write_text(desktop_entry)
|
|
185
|
+
print(f"Created {desktop_file}")
|
|
186
|
+
|
|
187
|
+
# Register as default handler
|
|
188
|
+
try:
|
|
189
|
+
subprocess.run(
|
|
190
|
+
["xdg-mime", "default", "mail-swarm.desktop", "x-scheme-handler/swarm"],
|
|
191
|
+
check=True,
|
|
192
|
+
)
|
|
193
|
+
print("Registered as default handler for swarm:// URLs")
|
|
194
|
+
except FileNotFoundError:
|
|
195
|
+
print("Warning: xdg-mime not found. Please run manually:")
|
|
196
|
+
print(" xdg-mime default mail-swarm.desktop x-scheme-handler/swarm")
|
|
197
|
+
except subprocess.CalledProcessError as e:
|
|
198
|
+
print(f"Error registering handler: {e}")
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def _register_macos() -> None:
|
|
202
|
+
"""
|
|
203
|
+
Print instructions for macOS URL handler registration.
|
|
204
|
+
"""
|
|
205
|
+
print("macOS URL handler registration requires app bundling.")
|
|
206
|
+
print()
|
|
207
|
+
print("To register swarm:// URLs, add this to your app's Info.plist:")
|
|
208
|
+
print()
|
|
209
|
+
print(" <key>CFBundleURLTypes</key>")
|
|
210
|
+
print(" <array>")
|
|
211
|
+
print(" <dict>")
|
|
212
|
+
print(" <key>CFBundleURLName</key>")
|
|
213
|
+
print(" <string>MAIL Swarm Protocol</string>")
|
|
214
|
+
print(" <key>CFBundleURLSchemes</key>")
|
|
215
|
+
print(" <array>")
|
|
216
|
+
print(" <string>swarm</string>")
|
|
217
|
+
print(" </array>")
|
|
218
|
+
print(" </dict>")
|
|
219
|
+
print(" </array>")
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def _register_windows() -> None:
|
|
223
|
+
"""
|
|
224
|
+
Print instructions for Windows URL handler registration.
|
|
225
|
+
"""
|
|
226
|
+
mail_path = sys.executable.replace("python", "mail")
|
|
227
|
+
print("Windows URL handler registration requires registry access.")
|
|
228
|
+
print()
|
|
229
|
+
print("Run these commands in an Administrator PowerShell:")
|
|
230
|
+
print()
|
|
231
|
+
print(' New-Item -Path "HKCU:\\Software\\Classes\\swarm" -Force')
|
|
232
|
+
print(
|
|
233
|
+
' Set-ItemProperty -Path "HKCU:\\Software\\Classes\\swarm" -Name "(Default)" -Value "URL:MAIL Swarm Protocol"'
|
|
234
|
+
)
|
|
235
|
+
print(
|
|
236
|
+
' Set-ItemProperty -Path "HKCU:\\Software\\Classes\\swarm" -Name "URL Protocol" -Value ""'
|
|
237
|
+
)
|
|
238
|
+
print(
|
|
239
|
+
' New-Item -Path "HKCU:\\Software\\Classes\\swarm\\shell\\open\\command" -Force'
|
|
240
|
+
)
|
|
241
|
+
print(
|
|
242
|
+
f' Set-ItemProperty -Path "HKCU:\\Software\\Classes\\swarm\\shell\\open\\command" -Name "(Default)" -Value \'"{mail_path}" client "%1"\''
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def _run_ping(args: argparse.Namespace) -> None:
|
|
247
|
+
"""
|
|
248
|
+
Ping a MAIL server to check connectivity.
|
|
249
|
+
"""
|
|
250
|
+
import httpx
|
|
251
|
+
|
|
252
|
+
url = args.url
|
|
253
|
+
# Handle swarm:// URLs
|
|
254
|
+
swarm_url = parse_swarm_url(url)
|
|
255
|
+
if swarm_url:
|
|
256
|
+
if not swarm_url.server:
|
|
257
|
+
print("Error: swarm:// URL must include a 'server' parameter")
|
|
258
|
+
sys.exit(1)
|
|
259
|
+
url = f"https://{swarm_url.server}"
|
|
260
|
+
|
|
261
|
+
try:
|
|
262
|
+
with httpx.Client(timeout=args.timeout) as client:
|
|
263
|
+
response = client.get(f"{url.rstrip('/')}/health")
|
|
264
|
+
response.raise_for_status()
|
|
265
|
+
data = response.json()
|
|
266
|
+
print(
|
|
267
|
+
f"✓ {data.get('swarm_name', 'MAIL server')} is {data.get('status', 'up')}"
|
|
268
|
+
)
|
|
269
|
+
except httpx.ConnectError:
|
|
270
|
+
print(f"✗ Cannot connect to {url}")
|
|
271
|
+
sys.exit(1)
|
|
272
|
+
except httpx.HTTPStatusError as e:
|
|
273
|
+
print(f"✗ Server returned {e.response.status_code}")
|
|
274
|
+
sys.exit(1)
|
|
275
|
+
except Exception as e:
|
|
276
|
+
print(f"✗ Error: {e}")
|
|
277
|
+
sys.exit(1)
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def main() -> None:
|
|
281
|
+
# top-level MAIL parser
|
|
282
|
+
parser = argparse.ArgumentParser(
|
|
283
|
+
prog="mail",
|
|
284
|
+
description="Multi-Agent Interface Layer reference implementation CLI",
|
|
285
|
+
epilog="For more information, see `README.md` and `docs/`",
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
# subparsers for each MAIL command
|
|
289
|
+
subparsers = parser.add_subparsers()
|
|
290
|
+
|
|
291
|
+
# command `server`
|
|
292
|
+
server_parser = subparsers.add_parser("server", help="start the MAIL server")
|
|
293
|
+
server_parser.set_defaults(func=_run_server_with_args)
|
|
294
|
+
server_parser.add_argument(
|
|
295
|
+
"-c",
|
|
296
|
+
"--config",
|
|
297
|
+
type=str,
|
|
298
|
+
required=False,
|
|
299
|
+
help="path to the MAIL configuration file",
|
|
300
|
+
)
|
|
301
|
+
server_parser.add_argument(
|
|
302
|
+
"-p",
|
|
303
|
+
"--port",
|
|
304
|
+
type=int,
|
|
305
|
+
required=False,
|
|
306
|
+
help="port to listen on",
|
|
307
|
+
)
|
|
308
|
+
server_parser.add_argument(
|
|
309
|
+
"-H",
|
|
310
|
+
"--host",
|
|
311
|
+
type=str,
|
|
312
|
+
required=False,
|
|
313
|
+
help="host to listen on",
|
|
314
|
+
)
|
|
315
|
+
server_parser.add_argument(
|
|
316
|
+
"-r",
|
|
317
|
+
"--reload",
|
|
318
|
+
action="store_true",
|
|
319
|
+
help="enable hot reloading",
|
|
320
|
+
)
|
|
321
|
+
server_parser.add_argument(
|
|
322
|
+
"-d",
|
|
323
|
+
"--debug",
|
|
324
|
+
action="store_true",
|
|
325
|
+
help="enable debug mode (enable optional endpoints)",
|
|
326
|
+
)
|
|
327
|
+
server_parser.add_argument(
|
|
328
|
+
"-n",
|
|
329
|
+
"--swarm-name",
|
|
330
|
+
type=str,
|
|
331
|
+
required=False,
|
|
332
|
+
help="name of the swarm",
|
|
333
|
+
)
|
|
334
|
+
server_parser.add_argument(
|
|
335
|
+
"-s",
|
|
336
|
+
"--swarm-source",
|
|
337
|
+
type=str,
|
|
338
|
+
required=False,
|
|
339
|
+
help="source of the swarm",
|
|
340
|
+
)
|
|
341
|
+
server_parser.add_argument(
|
|
342
|
+
"-rf",
|
|
343
|
+
"--swarm-registry",
|
|
344
|
+
type=str,
|
|
345
|
+
required=False,
|
|
346
|
+
help="registry file of the swarm",
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
# command `client`
|
|
350
|
+
client_parser = subparsers.add_parser("client", help="run the MAIL client")
|
|
351
|
+
client_parser.set_defaults(func=_run_client_with_args)
|
|
352
|
+
client_parser.add_argument(
|
|
353
|
+
"-c",
|
|
354
|
+
"--config",
|
|
355
|
+
type=str,
|
|
356
|
+
required=False,
|
|
357
|
+
help="path to the MAIL configuration file",
|
|
358
|
+
)
|
|
359
|
+
client_parser.add_argument(
|
|
360
|
+
"url",
|
|
361
|
+
type=str,
|
|
362
|
+
help="URL of the MAIL server (supports http://, https://, or swarm://)",
|
|
363
|
+
)
|
|
364
|
+
client_parser.add_argument(
|
|
365
|
+
"-ak",
|
|
366
|
+
"--api-key",
|
|
367
|
+
type=str,
|
|
368
|
+
required=False,
|
|
369
|
+
help="API key for the MAIL server",
|
|
370
|
+
)
|
|
371
|
+
client_parser.add_argument(
|
|
372
|
+
"-t",
|
|
373
|
+
"--timeout",
|
|
374
|
+
type=float,
|
|
375
|
+
required=False,
|
|
376
|
+
help="client request timeout time in seconds",
|
|
377
|
+
)
|
|
378
|
+
client_parser.add_argument(
|
|
379
|
+
"-v",
|
|
380
|
+
"--verbose",
|
|
381
|
+
action="store_true",
|
|
382
|
+
help="enable verbose output",
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
# command `version`
|
|
386
|
+
version_parser = subparsers.add_parser("version", help="print the version of MAIL")
|
|
387
|
+
version_parser.set_defaults(func=_print_version)
|
|
388
|
+
|
|
389
|
+
# command `db-init`
|
|
390
|
+
db_init_parser = subparsers.add_parser(
|
|
391
|
+
"db-init", help="initialize database tables for agent history persistence"
|
|
392
|
+
)
|
|
393
|
+
db_init_parser.set_defaults(func=_run_db_init)
|
|
394
|
+
|
|
395
|
+
# command `register`
|
|
396
|
+
register_parser = subparsers.add_parser(
|
|
397
|
+
"register", help="register as OS handler for swarm:// URLs"
|
|
398
|
+
)
|
|
399
|
+
register_parser.set_defaults(func=_register_url_handler)
|
|
400
|
+
|
|
401
|
+
# command `ping`
|
|
402
|
+
ping_parser = subparsers.add_parser(
|
|
403
|
+
"ping", help="check if a MAIL server is reachable"
|
|
404
|
+
)
|
|
405
|
+
ping_parser.set_defaults(func=_run_ping)
|
|
406
|
+
ping_parser.add_argument(
|
|
407
|
+
"url",
|
|
408
|
+
type=str,
|
|
409
|
+
help="URL of the MAIL server",
|
|
410
|
+
)
|
|
411
|
+
ping_parser.add_argument(
|
|
412
|
+
"-t",
|
|
413
|
+
"--timeout",
|
|
414
|
+
type=float,
|
|
415
|
+
default=5.0,
|
|
416
|
+
help="timeout in seconds (default: 5)",
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
# parse CLI args
|
|
420
|
+
args = parser.parse_args()
|
|
421
|
+
|
|
422
|
+
# if no command is provided, print the help
|
|
423
|
+
if not hasattr(args, "func"):
|
|
424
|
+
parser.print_help()
|
|
425
|
+
return
|
|
426
|
+
|
|
427
|
+
# run the command
|
|
428
|
+
args.func(args)
|
|
429
|
+
|
|
430
|
+
|
|
431
|
+
if __name__ == "__main__":
|
|
432
|
+
main()
|