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
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Charon Labs
|
|
3
|
+
|
|
4
|
+
"""Summarization actions for the Research Assistant swarm."""
|
|
5
|
+
|
|
6
|
+
import json
|
|
7
|
+
import re
|
|
8
|
+
from datetime import datetime, UTC
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from mail import action
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _extract_sentences(text: str) -> list[str]:
|
|
15
|
+
"""Extract sentences from text."""
|
|
16
|
+
# Simple sentence splitting
|
|
17
|
+
sentences = re.split(r"(?<=[.!?])\s+", text)
|
|
18
|
+
return [s.strip() for s in sentences if len(s.strip()) > 10]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _score_sentence_importance(sentence: str, all_sentences: list[str]) -> float:
|
|
22
|
+
"""Score sentence importance based on content features."""
|
|
23
|
+
score = 0.0
|
|
24
|
+
sentence_lower = sentence.lower()
|
|
25
|
+
|
|
26
|
+
# Position bonus (first sentences are often important)
|
|
27
|
+
if sentence in all_sentences[:3]:
|
|
28
|
+
score += 0.3
|
|
29
|
+
|
|
30
|
+
# Contains important indicators
|
|
31
|
+
importance_words = [
|
|
32
|
+
"important",
|
|
33
|
+
"key",
|
|
34
|
+
"main",
|
|
35
|
+
"significant",
|
|
36
|
+
"primary",
|
|
37
|
+
"crucial",
|
|
38
|
+
"essential",
|
|
39
|
+
"critical",
|
|
40
|
+
"major",
|
|
41
|
+
"notable",
|
|
42
|
+
"first",
|
|
43
|
+
"second",
|
|
44
|
+
"third",
|
|
45
|
+
"finally",
|
|
46
|
+
"however",
|
|
47
|
+
"therefore",
|
|
48
|
+
"in conclusion",
|
|
49
|
+
"as a result",
|
|
50
|
+
"research shows",
|
|
51
|
+
"data indicates",
|
|
52
|
+
]
|
|
53
|
+
for word in importance_words:
|
|
54
|
+
if word in sentence_lower:
|
|
55
|
+
score += 0.2
|
|
56
|
+
|
|
57
|
+
# Contains numbers (often factual/important)
|
|
58
|
+
if any(char.isdigit() for char in sentence):
|
|
59
|
+
score += 0.15
|
|
60
|
+
|
|
61
|
+
# Length penalty for very short or very long sentences
|
|
62
|
+
word_count = len(sentence.split())
|
|
63
|
+
if word_count < 5:
|
|
64
|
+
score -= 0.2
|
|
65
|
+
elif word_count > 50:
|
|
66
|
+
score -= 0.1
|
|
67
|
+
elif 15 <= word_count <= 30:
|
|
68
|
+
score += 0.1
|
|
69
|
+
|
|
70
|
+
return max(0, score)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _create_extractive_summary(text: str, max_sentences: int) -> str:
|
|
74
|
+
"""Create an extractive summary by selecting important sentences."""
|
|
75
|
+
sentences = _extract_sentences(text)
|
|
76
|
+
|
|
77
|
+
if len(sentences) <= max_sentences:
|
|
78
|
+
return " ".join(sentences)
|
|
79
|
+
|
|
80
|
+
# Score sentences
|
|
81
|
+
scored = [(s, _score_sentence_importance(s, sentences)) for s in sentences]
|
|
82
|
+
|
|
83
|
+
# Sort by score but maintain some original order
|
|
84
|
+
# Take top-scoring sentences
|
|
85
|
+
scored.sort(key=lambda x: x[1], reverse=True)
|
|
86
|
+
selected = scored[:max_sentences]
|
|
87
|
+
|
|
88
|
+
# Reorder by original position
|
|
89
|
+
selected_sentences = [s[0] for s in selected]
|
|
90
|
+
ordered = [s for s in sentences if s in selected_sentences]
|
|
91
|
+
|
|
92
|
+
return " ".join(ordered)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
SUMMARIZE_TEXT_PARAMETERS = {
|
|
96
|
+
"type": "object",
|
|
97
|
+
"properties": {
|
|
98
|
+
"text": {
|
|
99
|
+
"type": "string",
|
|
100
|
+
"description": "The text to summarize",
|
|
101
|
+
},
|
|
102
|
+
"max_length": {
|
|
103
|
+
"type": "integer",
|
|
104
|
+
"minimum": 50,
|
|
105
|
+
"maximum": 2000,
|
|
106
|
+
"description": "Maximum length of summary in characters (default: 500)",
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
"required": ["text"],
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
@action(
|
|
114
|
+
name="summarize_text",
|
|
115
|
+
description="Create a concise summary of longer text.",
|
|
116
|
+
parameters=SUMMARIZE_TEXT_PARAMETERS,
|
|
117
|
+
)
|
|
118
|
+
async def summarize_text(args: dict[str, Any]) -> str:
|
|
119
|
+
"""Summarize text to specified length."""
|
|
120
|
+
try:
|
|
121
|
+
text = args["text"]
|
|
122
|
+
max_length = args.get("max_length", 500)
|
|
123
|
+
except KeyError as e:
|
|
124
|
+
return f"Error: {e} is required"
|
|
125
|
+
|
|
126
|
+
if not text.strip():
|
|
127
|
+
return json.dumps({"error": "Text cannot be empty"})
|
|
128
|
+
|
|
129
|
+
original_length = len(text)
|
|
130
|
+
original_sentences = len(_extract_sentences(text))
|
|
131
|
+
|
|
132
|
+
# Estimate needed sentences for target length
|
|
133
|
+
avg_sentence_length = original_length / max(original_sentences, 1)
|
|
134
|
+
target_sentences = max(1, int(max_length / max(avg_sentence_length, 50)))
|
|
135
|
+
|
|
136
|
+
# Create summary
|
|
137
|
+
summary = _create_extractive_summary(text, target_sentences)
|
|
138
|
+
|
|
139
|
+
# Truncate if still too long
|
|
140
|
+
if len(summary) > max_length:
|
|
141
|
+
summary = summary[: max_length - 3].rsplit(" ", 1)[0] + "..."
|
|
142
|
+
|
|
143
|
+
compression_ratio = len(summary) / original_length if original_length > 0 else 1
|
|
144
|
+
|
|
145
|
+
result = {
|
|
146
|
+
"summary": summary,
|
|
147
|
+
"original_length": original_length,
|
|
148
|
+
"summary_length": len(summary),
|
|
149
|
+
"compression_ratio": round(compression_ratio, 2),
|
|
150
|
+
"original_sentences": original_sentences,
|
|
151
|
+
"summary_sentences": len(_extract_sentences(summary)),
|
|
152
|
+
"method": "extractive",
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return json.dumps(result)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
CREATE_BIBLIOGRAPHY_PARAMETERS = {
|
|
159
|
+
"type": "object",
|
|
160
|
+
"properties": {
|
|
161
|
+
"sources": {
|
|
162
|
+
"type": "array",
|
|
163
|
+
"items": {
|
|
164
|
+
"type": "object",
|
|
165
|
+
"properties": {
|
|
166
|
+
"title": {"type": "string"},
|
|
167
|
+
"author": {"type": "string"},
|
|
168
|
+
"url": {"type": "string"},
|
|
169
|
+
"date": {"type": "string"},
|
|
170
|
+
"source_type": {"type": "string"},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
"description": "Array of source objects with title, author, url, date, source_type",
|
|
174
|
+
},
|
|
175
|
+
"style": {
|
|
176
|
+
"type": "string",
|
|
177
|
+
"enum": ["apa", "mla", "chicago", "simple"],
|
|
178
|
+
"description": "Citation style (default: simple)",
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
"required": ["sources"],
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@action(
|
|
186
|
+
name="create_bibliography",
|
|
187
|
+
description="Format sources into a properly formatted bibliography.",
|
|
188
|
+
parameters=CREATE_BIBLIOGRAPHY_PARAMETERS,
|
|
189
|
+
)
|
|
190
|
+
async def create_bibliography(args: dict[str, Any]) -> str:
|
|
191
|
+
"""Create a formatted bibliography from sources."""
|
|
192
|
+
try:
|
|
193
|
+
sources = args["sources"]
|
|
194
|
+
style = args.get("style", "simple")
|
|
195
|
+
except KeyError as e:
|
|
196
|
+
return f"Error: {e} is required"
|
|
197
|
+
|
|
198
|
+
if not sources:
|
|
199
|
+
return json.dumps({"error": "At least one source is required"})
|
|
200
|
+
|
|
201
|
+
formatted_entries = []
|
|
202
|
+
|
|
203
|
+
for i, source in enumerate(sources, 1):
|
|
204
|
+
title = source.get("title", "Untitled")
|
|
205
|
+
author = source.get("author", "Unknown Author")
|
|
206
|
+
url = source.get("url", "")
|
|
207
|
+
date = source.get("date", "n.d.")
|
|
208
|
+
source_type = source.get("source_type", "web")
|
|
209
|
+
|
|
210
|
+
if style == "apa":
|
|
211
|
+
# APA style: Author. (Date). Title. URL
|
|
212
|
+
entry = f"{author}. ({date}). {title}."
|
|
213
|
+
if url:
|
|
214
|
+
entry += f" Retrieved from {url}"
|
|
215
|
+
elif style == "mla":
|
|
216
|
+
# MLA style: Author. "Title." Date. URL.
|
|
217
|
+
entry = f'{author}. "{title}." {date}.'
|
|
218
|
+
if url:
|
|
219
|
+
entry += f" {url}."
|
|
220
|
+
elif style == "chicago":
|
|
221
|
+
# Chicago style: Author. "Title." Accessed Date. URL.
|
|
222
|
+
entry = f'{author}. "{title}."'
|
|
223
|
+
if url:
|
|
224
|
+
entry += f" Accessed {datetime.now(UTC).strftime('%B %d, %Y')}. {url}."
|
|
225
|
+
else: # simple
|
|
226
|
+
# Simple style: numbered list
|
|
227
|
+
entry = f"[{i}] {title}"
|
|
228
|
+
if author != "Unknown Author":
|
|
229
|
+
entry += f" by {author}"
|
|
230
|
+
if date != "n.d.":
|
|
231
|
+
entry += f" ({date})"
|
|
232
|
+
if url:
|
|
233
|
+
entry += f" - {url}"
|
|
234
|
+
|
|
235
|
+
formatted_entries.append(
|
|
236
|
+
{
|
|
237
|
+
"index": i,
|
|
238
|
+
"formatted": entry,
|
|
239
|
+
"source_type": source_type,
|
|
240
|
+
"original": source,
|
|
241
|
+
}
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Create bibliography text
|
|
245
|
+
bibliography_text = "\n".join([e["formatted"] for e in formatted_entries])
|
|
246
|
+
|
|
247
|
+
result = {
|
|
248
|
+
"style": style,
|
|
249
|
+
"entry_count": len(formatted_entries),
|
|
250
|
+
"entries": formatted_entries,
|
|
251
|
+
"bibliography": bibliography_text,
|
|
252
|
+
"generated_at": datetime.now(UTC).isoformat(),
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return json.dumps(result)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Charon Labs
|
|
3
|
+
|
|
4
|
+
"""Summarizer agent for the Research Assistant 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 LiteLLMSummarizerFunction(LiteLLMActionAgentFunction):
|
|
14
|
+
"""
|
|
15
|
+
Summarizer agent that synthesizes research findings.
|
|
16
|
+
|
|
17
|
+
This agent creates concise summaries and formatted
|
|
18
|
+
bibliographies from research data.
|
|
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 = False,
|
|
30
|
+
enable_interswarm: bool = False,
|
|
31
|
+
can_complete_tasks: bool = False,
|
|
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 summarizer agent function."""
|
|
67
|
+
return super().__call__(messages, tool_choice)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Charon Labs
|
|
3
|
+
|
|
4
|
+
SYSPROMPT = """You are summarizer@{swarm}, the synthesis specialist for this research assistant swarm.
|
|
5
|
+
|
|
6
|
+
# Your Role
|
|
7
|
+
Synthesize research findings into clear, well-organized summaries and create formatted bibliographies.
|
|
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 "researcher")
|
|
12
|
+
- After summarizing, call `send_response(target=<sender>, subject="Re: ...", body=<your summary>)`
|
|
13
|
+
- Include the COMPLETE summary in your response body
|
|
14
|
+
|
|
15
|
+
# Tools
|
|
16
|
+
|
|
17
|
+
## Summarization Operations
|
|
18
|
+
- `summarize_text(text, max_length)`: Create a concise summary of longer text
|
|
19
|
+
- `create_bibliography(sources)`: Format sources into a proper bibliography
|
|
20
|
+
|
|
21
|
+
## Communication
|
|
22
|
+
- `send_response(target, subject, body)`: Reply to the agent who requested information
|
|
23
|
+
- `send_request(target, subject, body)`: Ask another agent for information
|
|
24
|
+
- `acknowledge_broadcast(note)`: Acknowledge a broadcast message
|
|
25
|
+
- `ignore_broadcast(reason)`: Ignore an irrelevant broadcast
|
|
26
|
+
|
|
27
|
+
# Workflow
|
|
28
|
+
|
|
29
|
+
1. Receive research findings from another agent
|
|
30
|
+
2. Organize the information logically
|
|
31
|
+
3. Call `summarize_text` to create a concise summary
|
|
32
|
+
4. If sources provided, call `create_bibliography` to format them
|
|
33
|
+
5. Call `send_response` with:
|
|
34
|
+
- Executive summary (key findings)
|
|
35
|
+
- Detailed summary (organized by theme)
|
|
36
|
+
- Bibliography (if applicable)
|
|
37
|
+
- Confidence notes or caveats
|
|
38
|
+
|
|
39
|
+
# Summary Structure
|
|
40
|
+
|
|
41
|
+
Good summaries include:
|
|
42
|
+
- **Key Findings**: 2-3 main takeaways
|
|
43
|
+
- **Background**: Brief context
|
|
44
|
+
- **Details**: Organized supporting information
|
|
45
|
+
- **Limitations**: What's uncertain or missing
|
|
46
|
+
- **Sources**: Properly formatted references
|
|
47
|
+
|
|
48
|
+
# Guidelines
|
|
49
|
+
|
|
50
|
+
- Lead with the most important findings
|
|
51
|
+
- Use clear, accessible language
|
|
52
|
+
- Maintain original meaning while condensing
|
|
53
|
+
- Preserve important nuances and caveats
|
|
54
|
+
- Include all cited sources in bibliography
|
|
55
|
+
- Use "Re: <original subject>" as your response subject"""
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
# Copyright (c) 2025 Charon Labs
|
|
3
|
+
|
|
4
|
+
"""Verifier agent for the Research Assistant swarm."""
|
|
5
|
+
|
|
6
|
+
from mail.examples.research.verifier.agent import LiteLLMVerifierFunction
|
|
7
|
+
from mail.examples.research.verifier.actions import verify_claim, rate_confidence
|
|
8
|
+
from mail.examples.research.verifier.prompts import SYSPROMPT
|
|
9
|
+
|
|
10
|
+
__all__ = ["LiteLLMVerifierFunction", "verify_claim", "rate_confidence", "SYSPROMPT"]
|