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/net/server_utils.py
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Addison Kline
|
|
3
|
+
|
|
4
|
+
import asyncio
|
|
5
|
+
import logging
|
|
6
|
+
|
|
7
|
+
from mail.api import MAILSwarm, MAILSwarmTemplate
|
|
8
|
+
from mail.config import ServerConfig
|
|
9
|
+
from mail.net.registry import SwarmRegistry
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def compute_external_base_url(cfg: ServerConfig) -> str:
|
|
15
|
+
"""
|
|
16
|
+
Derive an externally-reachable base URL from the server config.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
host = cfg.host
|
|
20
|
+
port = cfg.port
|
|
21
|
+
|
|
22
|
+
if host in {"0.0.0.0", "::"}:
|
|
23
|
+
# 0.0.0.0/:: listen on all interfaces; default to localhost for callbacks
|
|
24
|
+
host_for_url = "localhost"
|
|
25
|
+
else:
|
|
26
|
+
host_for_url = host
|
|
27
|
+
|
|
28
|
+
return f"http://{host_for_url}:{port}"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def get_default_persistent_swarm(
|
|
32
|
+
cfg: ServerConfig,
|
|
33
|
+
) -> MAILSwarmTemplate:
|
|
34
|
+
"""
|
|
35
|
+
Get the default persistent swarm template from the server config.
|
|
36
|
+
"""
|
|
37
|
+
swarm_name = cfg.swarm.name
|
|
38
|
+
swarm_json_file = cfg.swarm.source
|
|
39
|
+
|
|
40
|
+
return MAILSwarmTemplate.from_swarm_json_file(
|
|
41
|
+
swarm_name=swarm_name,
|
|
42
|
+
json_filepath=swarm_json_file,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def init_mail_instances_dict() -> dict[str, MAILSwarm]:
|
|
47
|
+
"""
|
|
48
|
+
Initialize the mail instances dictionary for a given role.
|
|
49
|
+
Should always be empty on startup.
|
|
50
|
+
"""
|
|
51
|
+
return {}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def init_mail_tasks_dict() -> dict[str, asyncio.Task]:
|
|
55
|
+
"""
|
|
56
|
+
Initialize the mail tasks dictionary for a given role.
|
|
57
|
+
Should always be empty on startup.
|
|
58
|
+
"""
|
|
59
|
+
return {}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_default_swarm_registry(
|
|
63
|
+
cfg: ServerConfig, swarm: MAILSwarmTemplate
|
|
64
|
+
) -> SwarmRegistry:
|
|
65
|
+
"""
|
|
66
|
+
Get the default swarm registry from the server config.
|
|
67
|
+
"""
|
|
68
|
+
swarm_name = swarm.name
|
|
69
|
+
swarm_registry_file = cfg.swarm.registry_file
|
|
70
|
+
local_base_url = get_default_base_url(cfg)
|
|
71
|
+
|
|
72
|
+
return SwarmRegistry(
|
|
73
|
+
local_swarm_name=swarm_name,
|
|
74
|
+
local_base_url=local_base_url,
|
|
75
|
+
persistence_file=swarm_registry_file,
|
|
76
|
+
local_swarm_description=swarm.description,
|
|
77
|
+
local_swarm_keywords=swarm.keywords,
|
|
78
|
+
local_swarm_public=swarm.public,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_default_swarm_name(
|
|
83
|
+
cfg: ServerConfig,
|
|
84
|
+
) -> str:
|
|
85
|
+
"""
|
|
86
|
+
Get the default swarm name from the server config.
|
|
87
|
+
"""
|
|
88
|
+
return cfg.swarm.name
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def get_default_base_url(
|
|
92
|
+
cfg: ServerConfig,
|
|
93
|
+
) -> str:
|
|
94
|
+
"""
|
|
95
|
+
Get the default base URL from the server config.
|
|
96
|
+
"""
|
|
97
|
+
return compute_external_base_url(cfg)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def get_default_entrypoint_agent(
|
|
101
|
+
swarm_template: MAILSwarmTemplate,
|
|
102
|
+
) -> str:
|
|
103
|
+
"""
|
|
104
|
+
Get the default entrypoint agent from the swarm template.
|
|
105
|
+
"""
|
|
106
|
+
return swarm_template.entrypoint
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def init_task_bindings_dict() -> dict[str, dict[str, str]]:
|
|
110
|
+
"""
|
|
111
|
+
Initialize the task bindings dictionary.
|
|
112
|
+
Should always be empty on startup.
|
|
113
|
+
"""
|
|
114
|
+
return {}
|
mail/net/types.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Addison Kline
|
|
3
|
+
|
|
4
|
+
import datetime
|
|
5
|
+
from typing import Any, TypedDict
|
|
6
|
+
|
|
7
|
+
from sse_starlette import ServerSentEvent
|
|
8
|
+
|
|
9
|
+
from mail.core.message import MAILMessage
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SwarmEndpoint(TypedDict):
|
|
13
|
+
"""
|
|
14
|
+
Represents a swarm endpoint for interswarm communication.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
swarm_name: str
|
|
18
|
+
"""The name of the swarm."""
|
|
19
|
+
base_url: str
|
|
20
|
+
"""The base URL of the swarm (e.g., https://swarm1.example.com)."""
|
|
21
|
+
version: str
|
|
22
|
+
"""The version of the swarm."""
|
|
23
|
+
health_check_url: str
|
|
24
|
+
"""The health check endpoint URL."""
|
|
25
|
+
auth_token_ref: str | None
|
|
26
|
+
"""Authentication token reference (environment variable or actual token)."""
|
|
27
|
+
last_seen: datetime.datetime | None
|
|
28
|
+
"""When this swarm was last seen/heard from."""
|
|
29
|
+
is_active: bool
|
|
30
|
+
"""Whether this swarm is currently active."""
|
|
31
|
+
latency: float | None
|
|
32
|
+
"""The latency of the swarm in seconds."""
|
|
33
|
+
swarm_description: str
|
|
34
|
+
"""The description of the swarm."""
|
|
35
|
+
keywords: list[str]
|
|
36
|
+
"""The keywords of the swarm."""
|
|
37
|
+
metadata: dict[str, Any] | None
|
|
38
|
+
"""Additional metadata about the swarm."""
|
|
39
|
+
public: bool
|
|
40
|
+
"""Whether this swarm is publicly accessible."""
|
|
41
|
+
volatile: bool
|
|
42
|
+
"""Whether this swarm is volatile (will be removed from the registry when the server shuts down)."""
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class SwarmEndpointCleaned(TypedDict):
|
|
46
|
+
"""
|
|
47
|
+
Represents a swarm endpoint for interswarm communication.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
swarm_name: str
|
|
51
|
+
"""The name of the swarm."""
|
|
52
|
+
base_url: str
|
|
53
|
+
"""The base URL of the swarm (e.g., https://swarm1.example.com)."""
|
|
54
|
+
version: str
|
|
55
|
+
"""The protocol version of the swarm."""
|
|
56
|
+
last_seen: datetime.datetime | None
|
|
57
|
+
"""When this swarm was last seen/heard from."""
|
|
58
|
+
is_active: bool
|
|
59
|
+
"""Whether this swarm is currently active."""
|
|
60
|
+
latency: float | None
|
|
61
|
+
"""The latency of the swarm in seconds."""
|
|
62
|
+
swarm_description: str
|
|
63
|
+
"""The description of the swarm."""
|
|
64
|
+
keywords: list[str]
|
|
65
|
+
"""The keywords of the swarm."""
|
|
66
|
+
metadata: dict[str, Any] | None
|
|
67
|
+
"""Additional metadata about the swarm."""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class SwarmInfo(TypedDict):
|
|
71
|
+
"""
|
|
72
|
+
Information about the current swarm.
|
|
73
|
+
"""
|
|
74
|
+
|
|
75
|
+
name: str
|
|
76
|
+
"""The name of the swarm."""
|
|
77
|
+
version: str
|
|
78
|
+
"""The protocol version of the swarm."""
|
|
79
|
+
description: str
|
|
80
|
+
"""The description of the swarm."""
|
|
81
|
+
entrypoint: str
|
|
82
|
+
"""The default entrypoint of the swarm."""
|
|
83
|
+
keywords: list[str]
|
|
84
|
+
"""The keywords of the swarm."""
|
|
85
|
+
public: bool
|
|
86
|
+
"""Whether this swarm is publicly accessible."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class SwarmStatus(TypedDict):
|
|
90
|
+
"""
|
|
91
|
+
The status of a swarm.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
name: str | None
|
|
95
|
+
"""The name of the swarm."""
|
|
96
|
+
status: str
|
|
97
|
+
"""The status of the swarm."""
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class GetRootResponse(TypedDict):
|
|
101
|
+
"""
|
|
102
|
+
Response for the MAIL server endpoint `GET /`.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
name: str
|
|
106
|
+
"""The name of the service; should always be `mail`."""
|
|
107
|
+
protocol_version: str
|
|
108
|
+
"""The version of the MAIL protocol that is being used."""
|
|
109
|
+
swarm: SwarmInfo
|
|
110
|
+
"""Information about the swarm that is running."""
|
|
111
|
+
status: str
|
|
112
|
+
"""The status of the service; should always be `running`."""
|
|
113
|
+
uptime: float
|
|
114
|
+
"""The uptime of the service in seconds."""
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class GetWhoamiResponse(TypedDict):
|
|
118
|
+
"""
|
|
119
|
+
Response for the MAIL server endpoint `GET /whoami`.
|
|
120
|
+
"""
|
|
121
|
+
|
|
122
|
+
id: str
|
|
123
|
+
"""The ID of the caller."""
|
|
124
|
+
role: str
|
|
125
|
+
"""The role of the caller."""
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
class GetStatusResponse(TypedDict):
|
|
129
|
+
"""
|
|
130
|
+
Response for the MAIL server endpoint `GET /status`.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
swarm: SwarmStatus
|
|
134
|
+
"""The swarm that is running."""
|
|
135
|
+
active_users: int
|
|
136
|
+
"""The number of active users."""
|
|
137
|
+
user_mail_ready: bool
|
|
138
|
+
"""Whether the user MAIL instance is ready."""
|
|
139
|
+
user_task_running: bool
|
|
140
|
+
"""Whether the user MAIL instance task is running."""
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
class PostMessageResponse(TypedDict):
|
|
144
|
+
"""
|
|
145
|
+
Response for the MAIL server endpoint `POST /message`.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
response: str
|
|
149
|
+
"""The response from the MAIL instance."""
|
|
150
|
+
events: list[ServerSentEvent] | None
|
|
151
|
+
"""The events from the MAIL instance."""
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
class GetHealthResponse(TypedDict):
|
|
155
|
+
"""
|
|
156
|
+
Response for the MAIL server endpoint `GET /health`.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
status: str
|
|
160
|
+
"""The status of the MAIL instance."""
|
|
161
|
+
swarm_name: str
|
|
162
|
+
"""The name of the swarm."""
|
|
163
|
+
timestamp: str
|
|
164
|
+
"""The timestamp of the response."""
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
class GetSwarmsResponse(TypedDict):
|
|
168
|
+
"""
|
|
169
|
+
Response for the MAIL server endpoint `GET /swarms`.
|
|
170
|
+
"""
|
|
171
|
+
|
|
172
|
+
swarms: list[SwarmEndpointCleaned]
|
|
173
|
+
"""The swarms that are running."""
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
class PostSwarmsResponse(TypedDict):
|
|
177
|
+
"""
|
|
178
|
+
Response for the MAIL server endpoint `POST /swarms`.
|
|
179
|
+
"""
|
|
180
|
+
|
|
181
|
+
status: str
|
|
182
|
+
"""The status of the response."""
|
|
183
|
+
swarm_name: str
|
|
184
|
+
"""The name of the swarm."""
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
class GetSwarmsDumpResponse(TypedDict):
|
|
188
|
+
"""
|
|
189
|
+
Response for the MAIL server endpoint `GET /swarms/dump`.
|
|
190
|
+
"""
|
|
191
|
+
|
|
192
|
+
status: str
|
|
193
|
+
"""The status of the response."""
|
|
194
|
+
swarm_name: str
|
|
195
|
+
"""The name of the swarm."""
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
class PostInterswarmMessageResponse(TypedDict):
|
|
199
|
+
"""
|
|
200
|
+
Response for the MAIL server endpoint `POST /interswarm/message`.
|
|
201
|
+
"""
|
|
202
|
+
|
|
203
|
+
response: MAILMessage
|
|
204
|
+
"""The response from the MAIL instance."""
|
|
205
|
+
events: list[ServerSentEvent] | None
|
|
206
|
+
"""The events from the MAIL instance."""
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class PostInterswarmForwardResponse(TypedDict):
|
|
210
|
+
"""
|
|
211
|
+
Response for the MAIL server endpoint `POST /interswarm/forward`.
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
swarm: str
|
|
215
|
+
"""The name of the swarm."""
|
|
216
|
+
task_id: str
|
|
217
|
+
"""The task ID of the interswarm message."""
|
|
218
|
+
status: str
|
|
219
|
+
"""The status of the response."""
|
|
220
|
+
local_runner: str
|
|
221
|
+
"""The local runner of the swarm (role:id@swarm)."""
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class PostInterswarmBackResponse(TypedDict):
|
|
225
|
+
"""
|
|
226
|
+
Response for the MAIL server endpoint `POST /interswarm/back`.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
swarm: str
|
|
230
|
+
"""The name of the swarm."""
|
|
231
|
+
task_id: str
|
|
232
|
+
"""The task ID of the interswarm message."""
|
|
233
|
+
status: str
|
|
234
|
+
"""The status of the response."""
|
|
235
|
+
local_runner: str
|
|
236
|
+
"""The local runner of the swarm (role:id@swarm)."""
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class PostSwarmsLoadResponse(TypedDict):
|
|
240
|
+
"""
|
|
241
|
+
Response for the MAIL server endpoint `POST /swarms/load`.
|
|
242
|
+
"""
|
|
243
|
+
|
|
244
|
+
status: str
|
|
245
|
+
"""The status of the response."""
|
|
246
|
+
swarm_name: str
|
|
247
|
+
"""The name of the swarm."""
|