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.
Files changed (137) hide show
  1. mail/__init__.py +35 -0
  2. mail/api.py +1964 -0
  3. mail/cli.py +432 -0
  4. mail/client.py +1657 -0
  5. mail/config/__init__.py +8 -0
  6. mail/config/client.py +87 -0
  7. mail/config/server.py +165 -0
  8. mail/core/__init__.py +72 -0
  9. mail/core/actions.py +69 -0
  10. mail/core/agents.py +73 -0
  11. mail/core/message.py +366 -0
  12. mail/core/runtime.py +3537 -0
  13. mail/core/tasks.py +311 -0
  14. mail/core/tools.py +1206 -0
  15. mail/db/__init__.py +0 -0
  16. mail/db/init.py +182 -0
  17. mail/db/types.py +65 -0
  18. mail/db/utils.py +523 -0
  19. mail/examples/__init__.py +27 -0
  20. mail/examples/analyst_dummy/__init__.py +15 -0
  21. mail/examples/analyst_dummy/agent.py +136 -0
  22. mail/examples/analyst_dummy/prompts.py +44 -0
  23. mail/examples/consultant_dummy/__init__.py +15 -0
  24. mail/examples/consultant_dummy/agent.py +136 -0
  25. mail/examples/consultant_dummy/prompts.py +42 -0
  26. mail/examples/data_analysis/__init__.py +40 -0
  27. mail/examples/data_analysis/analyst/__init__.py +9 -0
  28. mail/examples/data_analysis/analyst/agent.py +67 -0
  29. mail/examples/data_analysis/analyst/prompts.py +53 -0
  30. mail/examples/data_analysis/processor/__init__.py +13 -0
  31. mail/examples/data_analysis/processor/actions.py +293 -0
  32. mail/examples/data_analysis/processor/agent.py +67 -0
  33. mail/examples/data_analysis/processor/prompts.py +48 -0
  34. mail/examples/data_analysis/reporter/__init__.py +10 -0
  35. mail/examples/data_analysis/reporter/actions.py +187 -0
  36. mail/examples/data_analysis/reporter/agent.py +67 -0
  37. mail/examples/data_analysis/reporter/prompts.py +49 -0
  38. mail/examples/data_analysis/statistics/__init__.py +18 -0
  39. mail/examples/data_analysis/statistics/actions.py +343 -0
  40. mail/examples/data_analysis/statistics/agent.py +67 -0
  41. mail/examples/data_analysis/statistics/prompts.py +60 -0
  42. mail/examples/mafia/__init__.py +0 -0
  43. mail/examples/mafia/game.py +1537 -0
  44. mail/examples/mafia/narrator_tools.py +396 -0
  45. mail/examples/mafia/personas.py +240 -0
  46. mail/examples/mafia/prompts.py +489 -0
  47. mail/examples/mafia/roles.py +147 -0
  48. mail/examples/mafia/spec.md +350 -0
  49. mail/examples/math_dummy/__init__.py +23 -0
  50. mail/examples/math_dummy/actions.py +252 -0
  51. mail/examples/math_dummy/agent.py +136 -0
  52. mail/examples/math_dummy/prompts.py +46 -0
  53. mail/examples/math_dummy/types.py +5 -0
  54. mail/examples/research/__init__.py +39 -0
  55. mail/examples/research/researcher/__init__.py +9 -0
  56. mail/examples/research/researcher/agent.py +67 -0
  57. mail/examples/research/researcher/prompts.py +54 -0
  58. mail/examples/research/searcher/__init__.py +10 -0
  59. mail/examples/research/searcher/actions.py +324 -0
  60. mail/examples/research/searcher/agent.py +67 -0
  61. mail/examples/research/searcher/prompts.py +53 -0
  62. mail/examples/research/summarizer/__init__.py +18 -0
  63. mail/examples/research/summarizer/actions.py +255 -0
  64. mail/examples/research/summarizer/agent.py +67 -0
  65. mail/examples/research/summarizer/prompts.py +55 -0
  66. mail/examples/research/verifier/__init__.py +10 -0
  67. mail/examples/research/verifier/actions.py +337 -0
  68. mail/examples/research/verifier/agent.py +67 -0
  69. mail/examples/research/verifier/prompts.py +52 -0
  70. mail/examples/supervisor/__init__.py +11 -0
  71. mail/examples/supervisor/agent.py +4 -0
  72. mail/examples/supervisor/prompts.py +93 -0
  73. mail/examples/support/__init__.py +33 -0
  74. mail/examples/support/classifier/__init__.py +10 -0
  75. mail/examples/support/classifier/actions.py +307 -0
  76. mail/examples/support/classifier/agent.py +68 -0
  77. mail/examples/support/classifier/prompts.py +56 -0
  78. mail/examples/support/coordinator/__init__.py +9 -0
  79. mail/examples/support/coordinator/agent.py +67 -0
  80. mail/examples/support/coordinator/prompts.py +48 -0
  81. mail/examples/support/faq/__init__.py +10 -0
  82. mail/examples/support/faq/actions.py +182 -0
  83. mail/examples/support/faq/agent.py +67 -0
  84. mail/examples/support/faq/prompts.py +42 -0
  85. mail/examples/support/sentiment/__init__.py +15 -0
  86. mail/examples/support/sentiment/actions.py +341 -0
  87. mail/examples/support/sentiment/agent.py +67 -0
  88. mail/examples/support/sentiment/prompts.py +54 -0
  89. mail/examples/weather_dummy/__init__.py +23 -0
  90. mail/examples/weather_dummy/actions.py +75 -0
  91. mail/examples/weather_dummy/agent.py +136 -0
  92. mail/examples/weather_dummy/prompts.py +35 -0
  93. mail/examples/weather_dummy/types.py +5 -0
  94. mail/factories/__init__.py +27 -0
  95. mail/factories/action.py +223 -0
  96. mail/factories/base.py +1531 -0
  97. mail/factories/supervisor.py +241 -0
  98. mail/net/__init__.py +7 -0
  99. mail/net/registry.py +712 -0
  100. mail/net/router.py +728 -0
  101. mail/net/server_utils.py +114 -0
  102. mail/net/types.py +247 -0
  103. mail/server.py +1605 -0
  104. mail/stdlib/__init__.py +0 -0
  105. mail/stdlib/anthropic/__init__.py +0 -0
  106. mail/stdlib/fs/__init__.py +15 -0
  107. mail/stdlib/fs/actions.py +209 -0
  108. mail/stdlib/http/__init__.py +19 -0
  109. mail/stdlib/http/actions.py +333 -0
  110. mail/stdlib/interswarm/__init__.py +11 -0
  111. mail/stdlib/interswarm/actions.py +208 -0
  112. mail/stdlib/mcp/__init__.py +19 -0
  113. mail/stdlib/mcp/actions.py +294 -0
  114. mail/stdlib/openai/__init__.py +13 -0
  115. mail/stdlib/openai/agents.py +451 -0
  116. mail/summarizer.py +234 -0
  117. mail/swarms_json/__init__.py +27 -0
  118. mail/swarms_json/types.py +87 -0
  119. mail/swarms_json/utils.py +255 -0
  120. mail/url_scheme.py +51 -0
  121. mail/utils/__init__.py +53 -0
  122. mail/utils/auth.py +194 -0
  123. mail/utils/context.py +17 -0
  124. mail/utils/logger.py +73 -0
  125. mail/utils/openai.py +212 -0
  126. mail/utils/parsing.py +89 -0
  127. mail/utils/serialize.py +292 -0
  128. mail/utils/store.py +49 -0
  129. mail/utils/string_builder.py +119 -0
  130. mail/utils/version.py +20 -0
  131. mail_swarms-1.3.2.dist-info/METADATA +237 -0
  132. mail_swarms-1.3.2.dist-info/RECORD +137 -0
  133. mail_swarms-1.3.2.dist-info/WHEEL +4 -0
  134. mail_swarms-1.3.2.dist-info/entry_points.txt +2 -0
  135. mail_swarms-1.3.2.dist-info/licenses/LICENSE +202 -0
  136. mail_swarms-1.3.2.dist-info/licenses/NOTICE +10 -0
  137. mail_swarms-1.3.2.dist-info/licenses/THIRD_PARTY_NOTICES.md +12334 -0
@@ -0,0 +1,8 @@
1
+ from .client import ClientConfig
2
+ from .server import ServerConfig, SwarmConfig
3
+
4
+ __all__ = [
5
+ "ServerConfig",
6
+ "SwarmConfig",
7
+ "ClientConfig",
8
+ ]
mail/config/client.py ADDED
@@ -0,0 +1,87 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Addison Kline
3
+
4
+ from __future__ import annotations
5
+
6
+ import logging
7
+ import os
8
+ from functools import lru_cache
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ from pydantic import BaseModel, Field
13
+
14
+ try: # Python 3.11+
15
+ import tomllib
16
+ except ModuleNotFoundError: # pragma: no cover - fallback for older runtimes
17
+ try:
18
+ import tomli as tomllib # type: ignore[no-redef]
19
+ except ModuleNotFoundError: # pragma: no cover - hard fallback
20
+ tomllib = None # type: ignore[assignment]
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def _resolve_mail_config_path() -> Path | None:
26
+ """
27
+ Determine the best candidate path for `mail.toml`.
28
+ """
29
+
30
+ env_path = os.getenv("MAIL_CONFIG_PATH")
31
+ if env_path:
32
+ candidate = Path(env_path).expanduser()
33
+ if candidate.is_file():
34
+ return candidate
35
+ logger.debug(f"MAIL_CONFIG_PATH set to {candidate} but file missing")
36
+
37
+ cwd_candidate = Path.cwd() / "mail.toml"
38
+ if cwd_candidate.is_file():
39
+ return cwd_candidate
40
+
41
+ for ancestor in Path(__file__).resolve().parents:
42
+ candidate = ancestor / "mail.toml"
43
+ if candidate.is_file():
44
+ return candidate
45
+
46
+ return None
47
+
48
+
49
+ @lru_cache(maxsize=1)
50
+ def _client_defaults() -> dict[str, Any]:
51
+ """
52
+ Resolve client defaults from `mail.toml`, falling back to literals.
53
+ """
54
+
55
+ defaults: dict[str, Any] = {
56
+ "timeout": 3600.0,
57
+ "verbose": False,
58
+ }
59
+
60
+ if tomllib is None:
61
+ logger.debug("tomllib not available; using built-in client defaults")
62
+ return defaults
63
+
64
+ config_path = _resolve_mail_config_path()
65
+ if config_path is None:
66
+ logger.debug("mail.toml not found; using built-in client defaults")
67
+ return defaults
68
+
69
+ try:
70
+ with config_path.open("rb") as config_file:
71
+ raw_config = tomllib.load(config_file)
72
+ except Exception as e: # pragma: no cover - uncommon failure
73
+ logger.warning(f"failed to load {config_path}: {e}")
74
+ return defaults
75
+
76
+ client_section = raw_config.get("client")
77
+ if isinstance(client_section, dict):
78
+ if "timeout" in client_section:
79
+ defaults["timeout"] = float(client_section["timeout"])
80
+ if "verbose" in client_section:
81
+ defaults["verbose"] = bool(client_section["verbose"])
82
+ return defaults
83
+
84
+
85
+ class ClientConfig(BaseModel):
86
+ timeout: float = Field(default_factory=lambda: _client_defaults()["timeout"])
87
+ verbose: bool = Field(default_factory=lambda: _client_defaults()["verbose"])
mail/config/server.py ADDED
@@ -0,0 +1,165 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Addison Kline
3
+
4
+ from __future__ import annotations
5
+
6
+ import logging
7
+ import os
8
+ from functools import lru_cache
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ from pydantic import BaseModel, Field
13
+
14
+ try: # Python 3.11+
15
+ import tomllib
16
+ except ModuleNotFoundError: # pragma: no cover - fallback for older runtimes
17
+ try:
18
+ import tomli as tomllib # type: ignore[no-redef]
19
+ except ModuleNotFoundError: # pragma: no cover - hard fallback
20
+ tomllib = None # type: ignore[assignment]
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ def _resolve_mail_config_path() -> Path | None:
26
+ """
27
+ Determine the best candidate path for `mail.toml`.
28
+ """
29
+
30
+ env_path = os.getenv("MAIL_CONFIG_PATH")
31
+ if env_path:
32
+ candidate = Path(env_path).expanduser()
33
+ if candidate.is_file():
34
+ return candidate
35
+ logger.warning(f"MAIL_CONFIG_PATH set to {candidate} but file missing")
36
+
37
+ cwd_candidate = Path.cwd() / "mail.toml"
38
+ if cwd_candidate.is_file():
39
+ return cwd_candidate
40
+
41
+ for ancestor in Path(__file__).resolve().parents:
42
+ candidate = ancestor / "mail.toml"
43
+ if candidate.is_file():
44
+ return candidate
45
+
46
+ return None
47
+
48
+
49
+ @lru_cache(maxsize=1)
50
+ def _load_defaults_from_toml() -> tuple[dict[str, Any], dict[str, Any], dict[str, Any]]:
51
+ """
52
+ Read default server + swarm fields from `mail.toml` if available.
53
+ """
54
+
55
+ server_defaults: dict[str, Any] = {
56
+ "port": 8000,
57
+ "host": "0.0.0.0",
58
+ "reload": False,
59
+ "debug": False,
60
+ }
61
+ swarm_defaults: dict[str, Any] = {
62
+ "name": "example-no-proxy",
63
+ "source": "swarms.json",
64
+ "registry_file": "registries/example-no-proxy.json",
65
+ "description": "",
66
+ "keywords": [],
67
+ "public": False,
68
+ }
69
+ settings_defaults: dict[str, Any] = {
70
+ "task_message_limit": 15,
71
+ }
72
+
73
+ if tomllib is None:
74
+ logger.warning("tomllib not available; using built-in defaults")
75
+ return server_defaults, swarm_defaults, settings_defaults
76
+
77
+ config_path = _resolve_mail_config_path()
78
+ if config_path is None:
79
+ logger.warning("mail.toml not found; using built-in defaults")
80
+ return server_defaults, swarm_defaults, settings_defaults
81
+
82
+ try:
83
+ with config_path.open("rb") as config_file:
84
+ raw_config = tomllib.load(config_file)
85
+ except Exception as e: # pragma: no cover - uncommon failure
86
+ logger.warning(f"failed to load {config_path}: {e}")
87
+ return server_defaults, swarm_defaults, settings_defaults
88
+
89
+ server_section = raw_config.get("server")
90
+ if isinstance(server_section, dict):
91
+ server_defaults = {
92
+ "port": server_section.get("port", server_defaults["port"]),
93
+ "host": server_section.get("host", server_defaults["host"]),
94
+ "reload": server_section.get("reload", server_defaults["reload"]),
95
+ "debug": server_section.get("debug", server_defaults["debug"]),
96
+ }
97
+
98
+ swarm_section = server_section.get("swarm")
99
+ if isinstance(swarm_section, dict):
100
+ registry_value = swarm_section.get("registry")
101
+ if registry_value is None:
102
+ registry_value = swarm_section.get("registry_file")
103
+
104
+ swarm_defaults = {
105
+ "name": swarm_section.get("name", swarm_defaults["name"]),
106
+ "source": swarm_section.get("source", swarm_defaults["source"]),
107
+ "registry_file": registry_value or swarm_defaults["registry_file"],
108
+ "description": swarm_section.get(
109
+ "description", swarm_defaults["description"]
110
+ ),
111
+ "keywords": swarm_section.get("keywords", swarm_defaults["keywords"]),
112
+ "public": swarm_section.get("public", swarm_defaults["public"]),
113
+ }
114
+
115
+ settings_section = server_section.get("settings")
116
+ if isinstance(settings_section, dict):
117
+ settings_defaults = {
118
+ "task_message_limit": settings_section.get(
119
+ "task_message_limit", settings_defaults["task_message_limit"]
120
+ ),
121
+ }
122
+
123
+ logger.info(
124
+ f"server defaults resolved to {server_defaults} with swarm defaults {swarm_defaults}",
125
+ )
126
+ return server_defaults, swarm_defaults, settings_defaults
127
+
128
+
129
+ def _server_defaults() -> dict[str, Any]:
130
+ return _load_defaults_from_toml()[0]
131
+
132
+
133
+ def _swarm_defaults() -> dict[str, Any]:
134
+ return _load_defaults_from_toml()[1]
135
+
136
+
137
+ def _settings_defaults() -> dict[str, Any]:
138
+ return _load_defaults_from_toml()[2]
139
+
140
+
141
+ class SwarmConfig(BaseModel):
142
+ name: str = Field(default_factory=lambda: _swarm_defaults()["name"])
143
+ description: str = Field(default_factory=lambda: _swarm_defaults()["description"])
144
+ keywords: list[str] = Field(default_factory=lambda: _swarm_defaults()["keywords"])
145
+ public: bool = Field(default_factory=lambda: _swarm_defaults()["public"])
146
+ source: str = Field(default_factory=lambda: _swarm_defaults()["source"])
147
+ registry_file: str = Field(
148
+ default_factory=lambda: _swarm_defaults()["registry_file"]
149
+ )
150
+
151
+
152
+ class SettingsConfig(BaseModel):
153
+ task_message_limit: int = Field(
154
+ default_factory=lambda: _settings_defaults()["task_message_limit"]
155
+ )
156
+
157
+
158
+ class ServerConfig(BaseModel):
159
+ port: int = Field(default_factory=lambda: _server_defaults()["port"])
160
+ host: str = Field(default_factory=lambda: _server_defaults()["host"])
161
+ reload: bool = Field(default_factory=lambda: _server_defaults()["reload"])
162
+ debug: bool = Field(default_factory=lambda: _server_defaults()["debug"])
163
+
164
+ swarm: SwarmConfig = Field(default_factory=SwarmConfig)
165
+ settings: SettingsConfig = Field(default_factory=SettingsConfig)
mail/core/__init__.py ADDED
@@ -0,0 +1,72 @@
1
+ from .actions import ActionFunction, ActionOverrideFunction
2
+ from .agents import AgentCore, AgentFunction
3
+ from .message import (
4
+ MAILAddress,
5
+ MAILBroadcast,
6
+ MAILInterrupt,
7
+ MAILInterswarmMessage,
8
+ MAILMessage,
9
+ MAILRequest,
10
+ MAILResponse,
11
+ create_admin_address,
12
+ create_agent_address,
13
+ create_system_address,
14
+ create_user_address,
15
+ format_agent_address,
16
+ parse_agent_address,
17
+ )
18
+ from .runtime import MAILRuntime
19
+ from .tools import (
20
+ MAIL_TOOL_NAMES,
21
+ AgentToolCall,
22
+ convert_call_to_mail_message,
23
+ create_acknowledge_broadcast_tool,
24
+ create_broadcast_tool,
25
+ create_ignore_broadcast_tool,
26
+ create_interrupt_tool,
27
+ create_interswarm_broadcast_tool,
28
+ create_mail_tools,
29
+ create_request_tool,
30
+ create_response_tool,
31
+ create_supervisor_tools,
32
+ create_swarm_discovery_tool,
33
+ create_task_complete_tool,
34
+ pydantic_model_to_tool,
35
+ )
36
+
37
+ __all__ = [
38
+ "ActionFunction",
39
+ "ActionOverrideFunction",
40
+ "AgentFunction",
41
+ "AgentCore",
42
+ "AgentToolCall",
43
+ "MAILAddress",
44
+ "MAILBroadcast",
45
+ "MAILInterrupt",
46
+ "MAILInterswarmMessage",
47
+ "MAILMessage",
48
+ "MAILRequest",
49
+ "MAILResponse",
50
+ "create_agent_address",
51
+ "create_admin_address",
52
+ "create_system_address",
53
+ "create_user_address",
54
+ "format_agent_address",
55
+ "parse_agent_address",
56
+ "MAILRuntime",
57
+ "MAIL_TOOL_NAMES",
58
+ "AgentToolCall",
59
+ "convert_call_to_mail_message",
60
+ "create_acknowledge_broadcast_tool",
61
+ "create_broadcast_tool",
62
+ "create_ignore_broadcast_tool",
63
+ "create_interrupt_tool",
64
+ "create_interswarm_broadcast_tool",
65
+ "create_mail_tools",
66
+ "create_request_tool",
67
+ "create_response_tool",
68
+ "create_supervisor_tools",
69
+ "create_swarm_discovery_tool",
70
+ "create_task_complete_tool",
71
+ "pydantic_model_to_tool",
72
+ ]
mail/core/actions.py ADDED
@@ -0,0 +1,69 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Addison Kline, Ryan Heaton
3
+
4
+ from collections.abc import Awaitable, Callable
5
+ from typing import Any, Literal
6
+ import logging
7
+
8
+ from mail.core.tools import AgentToolCall
9
+
10
+ ActionFunction = Callable[[dict[str, Any]], Awaitable[str]]
11
+ """
12
+ A function that executes an action tool and returns the response.
13
+ """
14
+
15
+ ActionOverrideFunction = Callable[[dict[str, Any]], Awaitable[dict[str, Any] | str]]
16
+ """
17
+ A function that overrides an action tool and returns the response.
18
+ """
19
+
20
+
21
+ class ActionCore:
22
+ """
23
+ A bare-bones action structure.
24
+ Contains only the action function and essential metadata.
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ function: ActionFunction,
30
+ name: str,
31
+ parameters: dict[str, Any],
32
+ ):
33
+ self.name = name
34
+ self.parameters = parameters
35
+ self.function = function
36
+
37
+ async def execute(
38
+ self,
39
+ call: AgentToolCall,
40
+ actions: dict[str, "ActionCore"] | None = None,
41
+ action_override: ActionOverrideFunction | None = None,
42
+ ) -> tuple[Literal["success", "error"], dict[str, str]]:
43
+ """
44
+ Execute an action tool and return the response within a MAIL runtime.
45
+ """
46
+ logger = logging.getLogger("mail.actions")
47
+ if actions:
48
+ action = actions.get(self.name)
49
+ if action:
50
+ return await action.execute(call, action_override=action_override)
51
+
52
+ if not action_override:
53
+ try:
54
+ content = await self.function(call.tool_args)
55
+ return ("success", {"content": content})
56
+ except Exception as e:
57
+ return ("error", {"content": f"failed to execute action tool: {e}"})
58
+ else:
59
+ try:
60
+ response = await action_override(call) # type: ignore
61
+ logger.info(f"action override response: {response}")
62
+ if isinstance(response, str):
63
+ return ("success", {"content": response})
64
+ return ("success", response)
65
+ except Exception as e:
66
+ return (
67
+ "error",
68
+ {"content": f"failed to execute action override tool: {e}"},
69
+ )
mail/core/agents.py ADDED
@@ -0,0 +1,73 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Addison Kline, Ryan Heaton
3
+
4
+ from collections.abc import Awaitable, Callable
5
+ from typing import Any
6
+
7
+ from .actions import ActionCore
8
+ from .tools import AgentToolCall
9
+
10
+ AgentOutput = tuple[str | None, list[AgentToolCall]]
11
+ """
12
+ Response type of a MAIL agent containing a response and tool calls.
13
+ """
14
+
15
+ AgentFunction = Callable[
16
+ [list[dict[str, Any]], str | dict[str, str]],
17
+ Awaitable[AgentOutput],
18
+ ]
19
+ """
20
+ A function that takes a chat history and returns a response and tool calls.
21
+ """
22
+
23
+
24
+ class AgentCore:
25
+ """
26
+ A bare-bones agent structure.
27
+ Contains only the agent function and essential metadata.
28
+ """
29
+
30
+ def __init__(
31
+ self,
32
+ function: AgentFunction,
33
+ comm_targets: list[str],
34
+ actions: dict[str, ActionCore] | None = None,
35
+ enable_entrypoint: bool = False,
36
+ enable_interswarm: bool = False,
37
+ can_complete_tasks: bool = False,
38
+ ):
39
+ self.function = function
40
+ self.comm_targets = comm_targets
41
+ if actions is None:
42
+ self.actions = {}
43
+ else:
44
+ self.actions = actions
45
+ self.enable_entrypoint = enable_entrypoint
46
+ self.enable_interswarm = enable_interswarm
47
+ self.can_complete_tasks = can_complete_tasks
48
+
49
+ def can_access_action_or_tool(self, name: str) -> bool:
50
+ """
51
+ Check if the agent can access a tool by name.
52
+ """
53
+ match name:
54
+ case (
55
+ "send_request"
56
+ | "send_response"
57
+ | "send_interrupt"
58
+ | "send_broadcast"
59
+ | "acknowledge_broadcast"
60
+ | "ignore_broadcast"
61
+ | "help"
62
+ ):
63
+ return True
64
+ case "task_complete":
65
+ return self.can_complete_tasks
66
+ case _:
67
+ return name in self.actions
68
+
69
+ def can_access_action(self, action_name: str) -> bool:
70
+ """
71
+ Check if the agent can access an action by name.
72
+ """
73
+ return action_name in self.actions