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,307 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Charon Labs
3
+
4
+ """Ticket classification action for the Customer Support swarm."""
5
+
6
+ import json
7
+ import re
8
+ from typing import Any
9
+
10
+ from mail import action
11
+
12
+ # Keyword mappings for classification
13
+ CATEGORY_KEYWORDS = {
14
+ "billing": [
15
+ "payment",
16
+ "pay",
17
+ "charge",
18
+ "charged",
19
+ "invoice",
20
+ "bill",
21
+ "refund",
22
+ "subscription",
23
+ "cancel",
24
+ "price",
25
+ "pricing",
26
+ "cost",
27
+ "credit card",
28
+ "card",
29
+ "money",
30
+ "fee",
31
+ "upgrade",
32
+ "downgrade",
33
+ "renew",
34
+ "renewal",
35
+ ],
36
+ "technical": [
37
+ "bug",
38
+ "error",
39
+ "crash",
40
+ "not working",
41
+ "broken",
42
+ "issue",
43
+ "problem",
44
+ "feature",
45
+ "slow",
46
+ "loading",
47
+ "api",
48
+ "integration",
49
+ "code",
50
+ "export",
51
+ "import",
52
+ "sync",
53
+ "download",
54
+ "upload",
55
+ "connect",
56
+ "connection",
57
+ ],
58
+ "account": [
59
+ "login",
60
+ "password",
61
+ "reset",
62
+ "account",
63
+ "profile",
64
+ "email",
65
+ "locked",
66
+ "access",
67
+ "sign in",
68
+ "sign up",
69
+ "register",
70
+ "2fa",
71
+ "authentication",
72
+ "security",
73
+ "verify",
74
+ "verification",
75
+ "username",
76
+ "settings",
77
+ ],
78
+ "general": [
79
+ "question",
80
+ "help",
81
+ "support",
82
+ "information",
83
+ "info",
84
+ "how to",
85
+ "what is",
86
+ "where",
87
+ "when",
88
+ "feedback",
89
+ "suggestion",
90
+ "thanks",
91
+ "thank you",
92
+ "appreciate",
93
+ "curious",
94
+ "wondering",
95
+ ],
96
+ }
97
+
98
+ PRIORITY_KEYWORDS = {
99
+ "urgent": [
100
+ "urgent",
101
+ "emergency",
102
+ "asap",
103
+ "immediately",
104
+ "critical",
105
+ "outage",
106
+ "down",
107
+ "breach",
108
+ "hacked",
109
+ "compromised",
110
+ "lost all",
111
+ "cannot access",
112
+ "locked out",
113
+ "deadline",
114
+ "now",
115
+ "right now",
116
+ ],
117
+ "high": [
118
+ "important",
119
+ "serious",
120
+ "major",
121
+ "significant",
122
+ "blocking",
123
+ "stuck",
124
+ "cannot",
125
+ "can't",
126
+ "unable",
127
+ "frustrated",
128
+ "angry",
129
+ "unacceptable",
130
+ "terrible",
131
+ "awful",
132
+ "horrible",
133
+ "worst",
134
+ ],
135
+ "medium": [
136
+ "issue",
137
+ "problem",
138
+ "help",
139
+ "need",
140
+ "want",
141
+ "would like",
142
+ "please",
143
+ "soon",
144
+ "when",
145
+ "how long",
146
+ "waiting",
147
+ "expected",
148
+ ],
149
+ "low": [
150
+ "question",
151
+ "curious",
152
+ "wondering",
153
+ "just",
154
+ "maybe",
155
+ "might",
156
+ "feedback",
157
+ "suggestion",
158
+ "idea",
159
+ "thanks",
160
+ "fyi",
161
+ "minor",
162
+ ],
163
+ }
164
+
165
+
166
+ def _count_keyword_matches(text: str, keywords: list[str]) -> int:
167
+ """Count how many keywords appear in the text."""
168
+ text_lower = text.lower()
169
+ count = 0
170
+ for keyword in keywords:
171
+ # Use word boundary matching for better accuracy
172
+ pattern = r"\b" + re.escape(keyword) + r"\b"
173
+ if re.search(pattern, text_lower):
174
+ count += 1
175
+ return count
176
+
177
+
178
+ def _classify_category(text: str) -> tuple[str, float]:
179
+ """Classify the ticket category based on keyword matching."""
180
+ scores = {}
181
+ for category, keywords in CATEGORY_KEYWORDS.items():
182
+ scores[category] = _count_keyword_matches(text, keywords)
183
+
184
+ # Find the category with highest score
185
+ max_category = max(scores, key=lambda x: scores[x])
186
+ max_score = scores[max_category]
187
+
188
+ # Calculate confidence based on score differential
189
+ total_score = sum(scores.values())
190
+ if total_score == 0:
191
+ return "general", 0.3 # Default to general with low confidence
192
+
193
+ confidence = max_score / total_score if total_score > 0 else 0.5
194
+ return max_category, round(confidence, 2)
195
+
196
+
197
+ def _classify_priority(text: str) -> tuple[str, float]:
198
+ """Classify the ticket priority based on keyword matching."""
199
+ scores = {}
200
+ for priority, keywords in PRIORITY_KEYWORDS.items():
201
+ scores[priority] = _count_keyword_matches(text, keywords)
202
+
203
+ # Apply priority weighting (urgent keywords should have more weight)
204
+ weighted_scores = {
205
+ "urgent": scores["urgent"] * 4,
206
+ "high": scores["high"] * 3,
207
+ "medium": scores["medium"] * 2,
208
+ "low": scores["low"] * 1,
209
+ }
210
+
211
+ # Find the priority with highest weighted score
212
+ max_priority = max(weighted_scores, key=lambda x: weighted_scores[x])
213
+ max_score = weighted_scores[max_priority]
214
+
215
+ # Default to medium if no clear signal
216
+ if max_score == 0:
217
+ return "medium", 0.5
218
+
219
+ total_score = sum(weighted_scores.values())
220
+ confidence = max_score / total_score if total_score > 0 else 0.5
221
+ return max_priority, round(confidence, 2)
222
+
223
+
224
+ CLASSIFY_TICKET_PARAMETERS = {
225
+ "type": "object",
226
+ "properties": {
227
+ "text": {
228
+ "type": "string",
229
+ "description": "The customer support ticket text to classify",
230
+ },
231
+ },
232
+ "required": ["text"],
233
+ }
234
+
235
+
236
+ @action(
237
+ name="classify_ticket",
238
+ description="Classify a customer support ticket by category and priority level.",
239
+ parameters=CLASSIFY_TICKET_PARAMETERS,
240
+ )
241
+ async def classify_ticket(args: dict[str, Any]) -> str:
242
+ """Classify a support ticket and return category and priority."""
243
+ try:
244
+ text = args["text"]
245
+ except KeyError as e:
246
+ return f"Error: {e} is required"
247
+
248
+ if not text.strip():
249
+ return json.dumps({"error": "Ticket text cannot be empty"})
250
+
251
+ # Perform classification
252
+ category, category_confidence = _classify_category(text)
253
+ priority, priority_confidence = _classify_priority(text)
254
+
255
+ # Generate reasoning
256
+ reasoning_parts = []
257
+ if category_confidence >= 0.6:
258
+ reasoning_parts.append(f"Strong match for '{category}' category")
259
+ else:
260
+ reasoning_parts.append(f"Moderate match for '{category}' category")
261
+
262
+ if priority == "urgent":
263
+ reasoning_parts.append("Contains urgent/critical language")
264
+ elif priority == "high":
265
+ reasoning_parts.append(
266
+ "Indicates significant user frustration or blocking issue"
267
+ )
268
+ elif priority == "low":
269
+ reasoning_parts.append("Appears to be a general inquiry or minor issue")
270
+
271
+ result = {
272
+ "category": category,
273
+ "category_confidence": category_confidence,
274
+ "priority": priority,
275
+ "priority_confidence": priority_confidence,
276
+ "reasoning": ". ".join(reasoning_parts) + ".",
277
+ "suggested_actions": _get_suggested_actions(category, priority),
278
+ }
279
+
280
+ return json.dumps(result)
281
+
282
+
283
+ def _get_suggested_actions(category: str, priority: str) -> list[str]:
284
+ """Get suggested actions based on classification."""
285
+ actions = []
286
+
287
+ if priority == "urgent":
288
+ actions.append("Escalate to senior support immediately")
289
+ actions.append("Consider immediate callback if phone available")
290
+ elif priority == "high":
291
+ actions.append("Prioritize in support queue")
292
+ actions.append("Provide detailed response within 4 hours")
293
+
294
+ if category == "billing":
295
+ actions.append("Check customer's billing history")
296
+ actions.append("Verify subscription status")
297
+ elif category == "technical":
298
+ actions.append("Check for known issues or outages")
299
+ actions.append("Gather technical details if needed")
300
+ elif category == "account":
301
+ actions.append("Verify customer identity")
302
+ actions.append("Check account security flags")
303
+
304
+ if not actions:
305
+ actions.append("Respond with standard FAQ or support resources")
306
+
307
+ return actions
@@ -0,0 +1,68 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Charon Labs
3
+
4
+ """Classifier agent for the Customer Support swarm."""
5
+
6
+ from collections.abc import Awaitable
7
+ from typing import Any, Literal
8
+
9
+ from mail.core.agents import AgentOutput
10
+ from mail.factories.action import LiteLLMActionAgentFunction
11
+
12
+
13
+ class LiteLLMClassifierFunction(LiteLLMActionAgentFunction):
14
+ """
15
+ Ticket classifier agent that categorizes and prioritizes support tickets.
16
+
17
+ This agent analyzes customer messages to determine the appropriate
18
+ category (billing, technical, account, general) and priority level
19
+ (low, medium, high, urgent).
20
+ """
21
+
22
+ def __init__(
23
+ self,
24
+ name: str,
25
+ comm_targets: list[str],
26
+ tools: list[dict[str, Any]],
27
+ llm: str,
28
+ system: str,
29
+ user_token: str = "",
30
+ enable_entrypoint: bool = False,
31
+ enable_interswarm: bool = False,
32
+ can_complete_tasks: bool = False,
33
+ tool_format: Literal["completions", "responses"] = "responses",
34
+ exclude_tools: list[str] = [],
35
+ reasoning_effort: Literal["minimal", "low", "medium", "high"] | None = None,
36
+ thinking_budget: int | None = None,
37
+ max_tokens: int | None = None,
38
+ memory: bool = True,
39
+ use_proxy: bool = True,
40
+ _debug_include_mail_tools: bool = True,
41
+ ) -> None:
42
+ super().__init__(
43
+ name=name,
44
+ comm_targets=comm_targets,
45
+ tools=tools,
46
+ llm=llm,
47
+ system=system,
48
+ user_token=user_token,
49
+ enable_entrypoint=enable_entrypoint,
50
+ enable_interswarm=enable_interswarm,
51
+ can_complete_tasks=can_complete_tasks,
52
+ tool_format=tool_format,
53
+ exclude_tools=exclude_tools,
54
+ reasoning_effort=reasoning_effort,
55
+ thinking_budget=thinking_budget,
56
+ max_tokens=max_tokens,
57
+ memory=memory,
58
+ use_proxy=use_proxy,
59
+ _debug_include_mail_tools=_debug_include_mail_tools,
60
+ )
61
+
62
+ def __call__(
63
+ self,
64
+ messages: list[dict[str, Any]],
65
+ tool_choice: str | dict[str, str] = "required",
66
+ ) -> Awaitable[AgentOutput]:
67
+ """Execute the classifier agent function."""
68
+ return super().__call__(messages, tool_choice)
@@ -0,0 +1,56 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Charon Labs
3
+
4
+ SYSPROMPT = """You are classifier@{swarm}, the ticket classification specialist for this customer support swarm.
5
+
6
+ # Your Role
7
+ Classify customer support tickets by category and priority level to ensure proper routing and handling.
8
+
9
+ # Critical Rule: Responding
10
+ You CANNOT talk to users directly or call `task_complete`. You MUST use `send_response` to reply to the agent who contacted you.
11
+ - When you receive a request, note the sender (usually "coordinator")
12
+ - After classifying the ticket, call `send_response(target=<sender>, subject="Re: ...", body=<your classification>)`
13
+ - Include the FULL classification results in your response body
14
+
15
+ # Tools
16
+
17
+ ## Classification
18
+ - `classify_ticket(text)`: Analyze ticket text and return category + priority
19
+
20
+ ## Communication
21
+ - `send_response(target, subject, body)`: Reply to the agent who requested information
22
+ - `send_request(target, subject, body)`: Ask another agent for information (e.g., sentiment for urgent cases)
23
+ - `acknowledge_broadcast(note)`: Acknowledge a broadcast message
24
+ - `ignore_broadcast(reason)`: Ignore an irrelevant broadcast
25
+
26
+ # Workflow
27
+
28
+ 1. Receive request from another agent (note the sender)
29
+ 2. Call `classify_ticket` with the customer's message text
30
+ 3. Review the classification results
31
+ 4. Optionally request sentiment analysis for borderline cases
32
+ 5. Call `send_response` to the original sender with:
33
+ - Category (billing, technical, account, general)
34
+ - Priority (low, medium, high, urgent)
35
+ - Brief reasoning for the classification
36
+
37
+ # Classification Guidelines
38
+
39
+ **Categories:**
40
+ - billing: Payment issues, refunds, subscription changes, invoices
41
+ - technical: Bugs, errors, feature requests, how-to questions
42
+ - account: Login issues, profile changes, security concerns
43
+ - general: General inquiries, feedback, other topics
44
+
45
+ **Priority Levels:**
46
+ - urgent: Service outage, security breach, financial loss
47
+ - high: Significant issue affecting user's ability to use the service
48
+ - medium: Important but not blocking, workaround available
49
+ - low: Minor issue, general question, feedback
50
+
51
+ # Guidelines
52
+
53
+ - Be consistent in your classifications
54
+ - When in doubt, err on the side of higher priority
55
+ - Report the classification clearly with category and priority
56
+ - Use "Re: <original subject>" as your response subject"""
@@ -0,0 +1,9 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Charon Labs
3
+
4
+ """Coordinator agent for the Customer Support swarm."""
5
+
6
+ from mail.examples.support.coordinator.agent import LiteLLMCoordinatorFunction
7
+ from mail.examples.support.coordinator.prompts import SYSPROMPT
8
+
9
+ __all__ = ["LiteLLMCoordinatorFunction", "SYSPROMPT"]
@@ -0,0 +1,67 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Charon Labs
3
+
4
+ """Coordinator agent for the Customer Support swarm."""
5
+
6
+ from collections.abc import Awaitable
7
+ from typing import Any, Literal
8
+
9
+ from mail.core.agents import AgentOutput
10
+ from mail.factories.base import LiteLLMAgentFunction
11
+
12
+
13
+ class LiteLLMCoordinatorFunction(LiteLLMAgentFunction):
14
+ """
15
+ Coordinator agent that orchestrates the customer support workflow.
16
+
17
+ This agent serves as the entry point for customer inquiries and delegates
18
+ to specialist agents (faq, classifier, sentiment) as needed.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ name: str,
24
+ comm_targets: list[str],
25
+ tools: list[dict[str, Any]],
26
+ llm: str,
27
+ system: str,
28
+ user_token: str = "",
29
+ enable_entrypoint: bool = True,
30
+ enable_interswarm: bool = False,
31
+ can_complete_tasks: bool = True,
32
+ tool_format: Literal["completions", "responses"] = "responses",
33
+ exclude_tools: list[str] = [],
34
+ reasoning_effort: Literal["minimal", "low", "medium", "high"] | None = None,
35
+ thinking_budget: int | None = None,
36
+ max_tokens: int | None = None,
37
+ memory: bool = True,
38
+ use_proxy: bool = True,
39
+ _debug_include_mail_tools: bool = True,
40
+ ) -> None:
41
+ super().__init__(
42
+ name=name,
43
+ comm_targets=comm_targets,
44
+ tools=tools,
45
+ llm=llm,
46
+ system=system,
47
+ user_token=user_token,
48
+ enable_entrypoint=enable_entrypoint,
49
+ enable_interswarm=enable_interswarm,
50
+ can_complete_tasks=can_complete_tasks,
51
+ tool_format=tool_format,
52
+ exclude_tools=exclude_tools,
53
+ reasoning_effort=reasoning_effort,
54
+ thinking_budget=thinking_budget,
55
+ max_tokens=max_tokens,
56
+ memory=memory,
57
+ use_proxy=use_proxy,
58
+ _debug_include_mail_tools=_debug_include_mail_tools,
59
+ )
60
+
61
+ def __call__(
62
+ self,
63
+ messages: list[dict[str, Any]],
64
+ tool_choice: str | dict[str, str] = "required",
65
+ ) -> Awaitable[AgentOutput]:
66
+ """Execute the coordinator agent function."""
67
+ return super().__call__(messages, tool_choice)
@@ -0,0 +1,48 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Charon Labs
3
+
4
+ SYSPROMPT = """You are coordinator@{swarm}, the lead support coordinator for this customer service swarm.
5
+
6
+ # Your Role
7
+ Orchestrate the customer support workflow by routing inquiries to specialist agents and synthesizing their responses into helpful, professional answers.
8
+
9
+ # Critical Rules
10
+
11
+ 1. **You MUST call task_complete to end every task** - this is how the user receives their answer
12
+ 2. Delegate work to specialist agents based on the inquiry type:
13
+ - `faq` - For common questions that might be in the FAQ database
14
+ - `classifier` - To categorize and prioritize tickets
15
+ - `sentiment` - To analyze customer tone and detect escalation needs
16
+
17
+ # Available Agents
18
+
19
+ - **faq**: Searches the FAQ database for relevant answers. Use for common questions about products, policies, or procedures.
20
+ - **classifier**: Categorizes tickets by type (billing, technical, general, etc.) and assigns priority levels.
21
+ - **sentiment**: Analyzes customer sentiment and identifies if escalation to a human agent is needed.
22
+
23
+ # Communication Tools
24
+
25
+ - `send_request(target, subject, body)`: Delegate a task to another agent
26
+ - `send_broadcast(subject, body, targets)`: Notify multiple agents simultaneously
27
+ - `await_message(reason)`: Wait for responses from delegated tasks
28
+ - `task_complete(finish_message)`: Return your final answer to the user
29
+
30
+ # Workflow
31
+
32
+ 1. Receive customer inquiry
33
+ 2. Analyze what type of support is needed
34
+ 3. Delegate to appropriate agents:
35
+ - FAQ lookup for knowledge-based questions
36
+ - Classification for ticket routing
37
+ - Sentiment analysis for tone assessment
38
+ 4. Collect responses using `await_message`
39
+ 5. Synthesize information into a helpful response
40
+ 6. Call `task_complete` with your final answer
41
+
42
+ # Guidelines
43
+
44
+ - Be professional and empathetic in your final responses
45
+ - If sentiment analysis indicates high frustration, acknowledge it in your response
46
+ - If no FAQ answer exists, provide general guidance or suggest contacting support
47
+ - Always prioritize customer satisfaction
48
+ - Keep responses concise but complete"""
@@ -0,0 +1,10 @@
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Copyright (c) 2025 Charon Labs
3
+
4
+ """FAQ agent for the Customer Support swarm."""
5
+
6
+ from mail.examples.support.faq.agent import LiteLLMFaqFunction
7
+ from mail.examples.support.faq.actions import search_faq
8
+ from mail.examples.support.faq.prompts import SYSPROMPT
9
+
10
+ __all__ = ["LiteLLMFaqFunction", "search_faq", "SYSPROMPT"]