beswarm 0.2.39__py3-none-any.whl → 0.2.41__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.

Potentially problematic release.


This version of beswarm might be problematic. Click here for more details.

beswarm/tools/subtasks.py CHANGED
@@ -1,5 +1,5 @@
1
1
  import ast
2
-
2
+ from pathlib import Path
3
3
  from ..core import task_manager
4
4
  from ..aient.src.aient.plugins import register_tool, registry
5
5
 
@@ -23,11 +23,24 @@ def create_task(goal, tools, work_dir):
23
23
  Returns:
24
24
  str: 当任务成功完成时,返回字符串 "任务已完成"。
25
25
  """
26
+ # 获取 worker 函数,这是正确的
27
+ worker_fun = registry.tools["worker"]
28
+
29
+ # 将单个任务的参数封装成一个列表
26
30
  tasks_params = [
27
- {"goal": goal, "tools": ast.literal_eval(tools), "work_dir": work_dir, "cache_messages": True}
31
+ {
32
+ "goal": goal,
33
+ "tools": ast.literal_eval(tools) if isinstance(tools, str) else tools,
34
+ "work_dir": work_dir,
35
+ "cache_messages": True
36
+ }
28
37
  ]
29
- task_ids = task_manager.create_tasks(worker_fun, tasks_params)
30
- return task_ids
38
+
39
+ # 调用新的批量创建接口
40
+ task_ids = task_manager.create_tasks_batch(worker_fun, tasks_params)
41
+
42
+ # 返回新创建的单个任务ID
43
+ return f"子任务已提交到队列,ID: {task_ids[0]}" if task_ids else "任务提交失败"
31
44
 
32
45
  @register_tool()
33
46
  def resume_task(task_id, goal):
@@ -61,7 +74,7 @@ async def get_task_result():
61
74
  Returns:
62
75
  str: 子任务的执行结果。
63
76
  """
64
- running_tasks_num = len([task_id for task_id, task in task_manager.tasks_cache.items() if task_id != "root_path" and task.get("status") == "RUNNING"])
77
+ running_tasks_num = len([task_id for task_id, task in task_manager.tasks_cache.items() if task_id != "root_path" and task.get("status") in ["PENDING", "RUNNING"]])
65
78
  if running_tasks_num == 0:
66
79
  return "All tasks are finished."
67
80
  task_id, status, result = await task_manager.get_next_result()
@@ -71,7 +84,87 @@ async def get_task_result():
71
84
  f"Task ID: {task_id}\n",
72
85
  f"Status: {status.value}\n",
73
86
  f"Result: {result}\n\n",
74
- f"There are {len(unfinished_tasks)} unfinished tasks, unfinished task ids: {unfinished_tasks}" if unfinished_tasks else "All tasks are finished.",
87
+ f"There are {len(unfinished_tasks)} unfinished tasks, unfinished task ids: {unfinished_tasks[:5]} ..." if unfinished_tasks else "All tasks are finished.",
75
88
  ])
76
89
 
77
- return text
90
+ return text
91
+
92
+ import os
93
+ import csv
94
+ import json
95
+ @register_tool()
96
+ def create_tasks_from_csv(goal_template: str, csv_file_path: str, tools_json_str: str, base_work_dir: str):
97
+ """
98
+ 从一个CSV文件批量创建子任务。
99
+ 此工具读取CSV文件的每一行,使用行数据填充goal模板,然后为每一行创建一个新的子任务。
100
+
101
+ Args:
102
+ goal_template (str): 一个包含占位符的字符串模板。占位符的格式应为 `{column_name}`,
103
+ 其中 `column_name` 对应CSV文件中的列名。
104
+ csv_file_path (str): 输入的CSV文件的完整路径。CSV文件的第一行必须是列标题。
105
+ tools_json_str (str): 一个JSON格式的字符串,表示所有子任务可用的工具列表。
106
+ 例如: '["read_file", "write_to_file"]'。
107
+ base_work_dir (str): 所有子任务工作目录的根路径。每个子任务将在此目录下
108
+ 创建一个以其唯一标识(如CSV中的id列)命名的子目录。base_work_dir **禁止** 设置为主任务目录本身。
109
+
110
+ Returns:
111
+ str: 批量创建任务的执行摘要,或在发生错误时返回错误信息。
112
+ """
113
+ # 1. 校验输入参数
114
+ if not os.path.exists(csv_file_path):
115
+ return f"<tool_error>CSV文件不存在: {csv_file_path}</tool_error>"
116
+
117
+ Path(base_work_dir).mkdir(parents=True, exist_ok=True)
118
+
119
+ try:
120
+ tools_list = json.loads(tools_json_str)
121
+ if not isinstance(tools_list, list):
122
+ raise ValueError("工具列表必须是一个JSON数组。")
123
+ except (json.JSONDecodeError, ValueError) as e:
124
+ return f"<tool_error>解析工具列表时出错: {e}</tool_error>"
125
+
126
+ tasks_params_list = []
127
+
128
+ try:
129
+ # 2. 读取并处理CSV文件
130
+ with open(csv_file_path, mode='r', encoding='utf-8') as csvfile:
131
+ # 使用 DictReader 可以方便地通过列名访问数据
132
+ reader = csv.DictReader(csvfile)
133
+
134
+ for index, row in enumerate(reader):
135
+ try:
136
+ # 3. 填充goal模板
137
+ # 使用.format_map()可以安全地处理模板中不存在的占位符
138
+ final_goal = goal_template.format_map(row)
139
+
140
+ # 4. 为每个任务创建独立的子工作目录
141
+ # 优先使用名为 'id' 或 'paper_id' 的列作为子目录名,以保证唯一性
142
+ # 如果没有,则使用行号作为后备
143
+ sub_dir_name = row.get('id', f"task_{index+1}")
144
+ task_work_dir = Path(base_work_dir) / sub_dir_name
145
+ # task_work_dir.mkdir(parents=True, exist_ok=True)
146
+
147
+ # 5. 准备任务参数
148
+ params = {
149
+ "goal": final_goal,
150
+ "tools": tools_list,
151
+ "work_dir": str(task_work_dir),
152
+ "cache_messages": True
153
+ }
154
+ tasks_params_list.append(params)
155
+
156
+ except KeyError as e:
157
+ return f"<tool_error>模板填充错误:CSV文件中缺少名为 '{e}' 的列。</tool_error>"
158
+
159
+ except Exception as e:
160
+ return f"<tool_error>处理CSV文件时发生错误: {e}</tool_error>"
161
+
162
+ if not tasks_params_list:
163
+ return "CSV文件为空或格式不正确,没有创建任何任务。"
164
+
165
+ # 6. 调用TaskManager批量提交任务
166
+ try:
167
+ task_ids = task_manager.create_tasks_batch(worker_fun, tasks_params_list)
168
+ return f"成功从CSV文件提交了 {len(task_ids)} 个任务到待处理队列。"
169
+ except Exception as e:
170
+ return f"<tool_error>提交任务到TaskManager时发生错误: {e}</tool_error>"
@@ -0,0 +1,35 @@
1
+ import csv
2
+ import ast
3
+ import os
4
+ from ..aient.src.aient.plugins import register_tool
5
+
6
+ @register_tool()
7
+ def append_row_to_csv(file_path: str, data: list):
8
+ """
9
+ 将一行数据安全地追加到CSV文件中。
10
+ 此工具会自动处理包含逗号、引号等特殊字符的字段,确保CSV格式的正确性。
11
+
12
+ Args:
13
+ file_path (str): 目标CSV文件的路径。
14
+ data (list): 一个代表单行数据的列表,列表中的每个元素对应CSV的一列。
15
+ 例如: ['1911.00484v4', 'irrelevant', '这段文本,可以包含逗号', 0.0]
16
+
17
+ Returns:
18
+ str: 操作成功或失败的提示信息。
19
+ """
20
+ try:
21
+ # 使用 'a+' 模式,以便在写入前检查文件末尾
22
+ with open(file_path, 'a+', newline='', encoding='utf-8') as file:
23
+ file.seek(0, os.SEEK_END) # 移动到文件末尾
24
+ # 如果文件非空,且最后一个字符不是换行符,则添加一个
25
+ if file.tell() > 0:
26
+ file.seek(file.tell() - 1, os.SEEK_SET)
27
+ if file.read(1) != '\n':
28
+ file.write('\n')
29
+
30
+ writer = csv.writer(file, quoting=csv.QUOTE_MINIMAL)
31
+ writer.writerow(ast.literal_eval(data) if isinstance(data, str) else data)
32
+
33
+ return f"已成功将一行数据追加到 {file_path}"
34
+ except Exception as e:
35
+ return f"<tool_error>写入CSV文件 {file_path} 时发生错误: {e}</tool_error>"
beswarm/utils.py CHANGED
@@ -1,4 +1,7 @@
1
1
  import re
2
+ import sys
3
+ import logging
4
+ from pathlib import Path
2
5
 
3
6
  def extract_xml_content(text, xml_tag):
4
7
  result = ''
@@ -164,6 +167,49 @@ async def {tool_name}({params_str}):
164
167
  print(f"Failed to create or register function for tool '{tool_name}': {e}")
165
168
  traceback.print_exc()
166
169
 
170
+ def setup_logger(logger_name: str, log_file: Path):
171
+ """
172
+ 用最简单的方式设置一个 logger,使其同时输出到文件和终端。
173
+
174
+ Args:
175
+ logger_name (str): Logger 的唯一名称。
176
+ log_file (Path): 日志文件的完整路径。
177
+
178
+ Returns:
179
+ logging.Logger: 配置好的 logger 实例。
180
+ """
181
+ # 1. 获取 Logger 实例
182
+ logger = logging.getLogger(logger_name)
183
+ logger.setLevel(logging.INFO) # 设置 logger 的最低处理级别为 INFO
184
+ logger.propagate = False
185
+
186
+ if logger.hasHandlers():
187
+ return logger
188
+
189
+ # 2. 创建文件 Handler
190
+ # 确保日志文件所在的目录存在
191
+ log_file.parent.mkdir(parents=True, exist_ok=True)
192
+ file_handler = logging.FileHandler(log_file, mode='a', encoding='utf-8')
193
+
194
+ # 3. 创建终端 Handler
195
+ # 使用 sys.stdout 可以确保输出在标准输出流,与 print() 行为一致
196
+ stream_handler = logging.StreamHandler(sys.stdout)
197
+
198
+ # 4. 创建一个通用的 Formatter
199
+ formatter = logging.Formatter('%(asctime)s - %(name)s - [%(levelname)s] - %(message)s')
200
+
201
+ # 5. 为两个 Handler 设置 Formatter
202
+ file_handler.setFormatter(formatter)
203
+ stream_handler.setFormatter(formatter)
204
+
205
+ # 6. 将两个 Handler 添加到 Logger
206
+ # DEBUG = os.getenv("DEBUG", "false").lower() in ("true", "1", "t", "yes")
207
+ logger.addHandler(file_handler)
208
+ logger.addHandler(stream_handler)
209
+ logger.propagate = False
210
+
211
+ return logger
212
+
167
213
  if __name__ == "__main__":
168
214
  print(extract_xml_content("<instructions>\n123</instructions>", "instructions"))
169
215
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.2.39
3
+ Version: 0.2.41
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -2,18 +2,18 @@ beswarm/__init__.py,sha256=HZjUOJtZR5QhMuDbq-wukQQn1VrBusNWai_ysGo-VVI,20
2
2
  beswarm/broker.py,sha256=RtnQZVbhf25acUHahNBiaS5FGxcrj0rhBhkon9gFY_M,9873
3
3
  beswarm/core.py,sha256=_J_LPc0HZFQTLGHy021OMEh2WbsjL_hc6jxd2engpyY,216
4
4
  beswarm/prompt.py,sha256=5JMfOuXWHscsaeDzwBn223mj9N85eAQdOHXQZk7zeWE,32238
5
- beswarm/taskmanager.py,sha256=oyvmxZmiguUXx1vYDQIuHS_GKDHEoDBhQ2Bjo4s128Q,9329
6
- beswarm/utils.py,sha256=xxbNifOPlfcVkKmF_qFzuEnZgF3MQg3mnOfz1EF0Qss,6697
5
+ beswarm/taskmanager.py,sha256=_v1lNHu9WpKK2ial22hvEVPzMJBUiaKTSUbXOxpEYlU,12119
6
+ beswarm/utils.py,sha256=S9jEtht0hTZbjZ2Hk24p4Ip41R69BogOkYS6fgPKY2Y,8219
7
7
  beswarm/agents/chatgroup.py,sha256=4QTjTjssFDvS2kI5A58TdN92BWjL-XaNzrcd36pTQGQ,11939
8
- beswarm/agents/planact.py,sha256=scnejgVzEf3bkKSIn8SQtUjTobz1s3Csb1noCRMg0YQ,17553
8
+ beswarm/agents/planact.py,sha256=BFUbz_e1PxZ-_Z6eYRhqejidmWTFo1CI1JWxFV6nTWo,17299
9
9
  beswarm/aient/main.py,sha256=SiYAIgQlLJqYusnTVEJOx1WNkSJKMImhgn5aWjfroxg,3814
10
- beswarm/aient/setup.py,sha256=lSEY6pYNdIdUB8F3gkj0XsEos1FMkd_c6PfIt-hscII,487
10
+ beswarm/aient/setup.py,sha256=Mq1M05mT9_UYBK2jk5mP_sLxKQAolcuh8PYXexfj-XU,487
11
11
  beswarm/aient/src/aient/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
12
12
  beswarm/aient/src/aient/core/__init__.py,sha256=NxjebTlku35S4Dzr16rdSqSTWUvvwEeACe8KvHJnjPg,34
13
13
  beswarm/aient/src/aient/core/log_config.py,sha256=kz2_yJv1p-o3lUQOwA3qh-LSc3wMHv13iCQclw44W9c,274
14
14
  beswarm/aient/src/aient/core/models.py,sha256=d4MISNezTSe0ls0-fjuToI2SoT-sk5fWqAJuKVinIlo,7502
15
- beswarm/aient/src/aient/core/request.py,sha256=GrB8hQY1K8AF1O9f5g-hoY8fwZR4SUNNhvCDpuhHVl0,76822
16
- beswarm/aient/src/aient/core/response.py,sha256=LwaDyCuuT0RPxBwE08k8_Dmh0df_q7q4BUix7NcCJV8,33207
15
+ beswarm/aient/src/aient/core/request.py,sha256=M1AfroPgFDG7oTLE2gisvR4BdkUeWqoTwfpxl_nxYB8,76923
16
+ beswarm/aient/src/aient/core/response.py,sha256=ekcMXxllCyrN9LDEdPttXrLvfcAY2sBqlkJBXxH7H6I,33667
17
17
  beswarm/aient/src/aient/core/utils.py,sha256=8TR442o3VV7Kl9l6f6LlmOUQ1UDZ-aXMzQqm-qIrqE4,28166
18
18
  beswarm/aient/src/aient/core/test/test_base_api.py,sha256=pWnycRJbuPSXKKU9AQjWrMAX1wiLC_014Qc9hh5C2Pw,524
19
19
  beswarm/aient/src/aient/core/test/test_geminimask.py,sha256=HFX8jDbNg_FjjgPNxfYaR-0-roUrOO-ND-FVsuxSoiw,13254
@@ -22,7 +22,7 @@ beswarm/aient/src/aient/core/test/test_payload.py,sha256=8jBiJY1uidm1jzL-EiK0s6U
22
22
  beswarm/aient/src/aient/models/__init__.py,sha256=ouNDNvoBBpIFrLsk09Q_sq23HR0GbLAKfGLIFmfEuXE,219
23
23
  beswarm/aient/src/aient/models/audio.py,sha256=kRd-8-WXzv4vwvsTGwnstK-WR8--vr9CdfCZzu8y9LA,1934
24
24
  beswarm/aient/src/aient/models/base.py,sha256=z-Z0pJfTN2x0cuwfvu0BdMRY9O-RmLwHEnBIJN1x4Fg,6719
25
- beswarm/aient/src/aient/models/chatgpt.py,sha256=UP7cn6Vo0bXzj6FpqTHIOjg1UygYQDXMSlUbXbH1uU4,47118
25
+ beswarm/aient/src/aient/models/chatgpt.py,sha256=LXSMwKRIbWIaPa1Ejk8oCEXVmjZ0rpgFLss35Attn-Q,53493
26
26
  beswarm/aient/src/aient/models/claude.py,sha256=JezghW7y0brl4Y5qiSHvnYR5prQCFywX4RViHt39pGI,26037
27
27
  beswarm/aient/src/aient/models/duckduckgo.py,sha256=1l7vYCs9SG5SWPCbcl7q6pCcB5AUF_r-a4l9frz3Ogo,8115
28
28
  beswarm/aient/src/aient/models/gemini.py,sha256=chGLc-8G_DAOxr10HPoOhvVFW1RvMgHd6mt--VyAW98,14730
@@ -41,14 +41,14 @@ beswarm/aient/src/aient/plugins/readonly.py,sha256=qK5-kBM3NDH1b-otFxFHpAjV5BXEY
41
41
  beswarm/aient/src/aient/plugins/registry.py,sha256=YknzhieU_8nQ3oKlUSSWDB4X7t2Jx0JnqT2Jd9Xsvfk,3574
42
42
  beswarm/aient/src/aient/plugins/run_python.py,sha256=MohvdtZUTDLrHBDtJ9L2_Qu1pWAGrkbzsGmmn5tMN20,4614
43
43
  beswarm/aient/src/aient/plugins/websearch.py,sha256=9yImBa1s5V7Djqzx6L4naDyIsGIcf_js1LOyLX0aNHw,15338
44
- beswarm/aient/src/aient/plugins/write_file.py,sha256=hExFLuoNPtjYxJI3pVbofZRpokvUabpXdEkd3mZJPPc,3778
44
+ beswarm/aient/src/aient/plugins/write_file.py,sha256=9msWSxWfJNhawLA-CyLLxtLipm53AX8o0VyCSV6VieM,3953
45
45
  beswarm/aient/src/aient/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  beswarm/aient/src/aient/utils/prompt.py,sha256=UcSzKkFE4-h_1b6NofI6xgk3GoleqALRKY8VBaXLjmI,11311
47
47
  beswarm/aient/src/aient/utils/scripts.py,sha256=h7EA2xBydUF_wdZLsPgjCq4Egdycx1gf2qrdrm0I7y0,40909
48
48
  beswarm/aient/test/chatgpt.py,sha256=Hvl7FuDt1c74N5TVBmhErOPvJbJJzA7FNp5VoZM4u30,4957
49
49
  beswarm/aient/test/claude.py,sha256=IyB4qI1eJLwlSfDNSnt2FhbQWYyBighHUjJxEXc3osQ,1095
50
50
  beswarm/aient/test/test.py,sha256=rldnoLQdtRR8IKFSIzTti7eIK2MpPMoi9gL5qD8_K44,29
51
- beswarm/aient/test/test_API.py,sha256=4Cz0raphXT8JywBxwK0SWSp-coY0--wvZpvFbtbqJ2g,251
51
+ beswarm/aient/test/test_API.py,sha256=kgXiFI_Jf5pXouhOq3dS5H960Bffvw7NEJLVkIkYI1k,229
52
52
  beswarm/aient/test/test_Deepbricks.py,sha256=EQwwNrTMHV4CEcZKdwUVGrwtNUsF0CCKbM-_W9IOYsk,693
53
53
  beswarm/aient/test/test_Web_crawler.py,sha256=l-DY0xwVPBfeEitUASkcIf19b4XwGrN-Ql_p7Dsbg_A,11410
54
54
  beswarm/aient/test/test_aiwaves.py,sha256=syZBxeWXyK7GMOykjXFpAoBFHgPS6x7pffquEHsNGWo,2486
@@ -130,19 +130,20 @@ beswarm/queries/tree-sitter-languages/ruby-tags.scm,sha256=vIidsCeE2A0vdFN18yXKq
130
130
  beswarm/queries/tree-sitter-languages/rust-tags.scm,sha256=9ljM1nzhfPs_ZTRw7cr2P9ToOyhGcKkCoN4_HPXSWi4,1451
131
131
  beswarm/queries/tree-sitter-languages/scala-tags.scm,sha256=UxQjz80JIrrJ7Pm56uUnQyThfmQNvwk7aQzPNypB-Ao,1761
132
132
  beswarm/queries/tree-sitter-languages/typescript-tags.scm,sha256=OMdCeedPiA24ky82DpgTMKXK_l2ySTuF2zrQ2fJAi9E,1253
133
- beswarm/tools/__init__.py,sha256=1GXl3alnff20BRRAg7YrSo9jBDbR0yOsD6bt41pGIj4,1476
133
+ beswarm/tools/__init__.py,sha256=frEg4AuVdO1m-xf9bdN-mgxh5f8O9UCGXUADahU5CcI,1594
134
134
  beswarm/tools/click.py,sha256=7g6x1X7ffTInGWp7112KS-MAQ5-8wa1Ze2sIipUIbjc,20884
135
- beswarm/tools/completion.py,sha256=BHMMZeDCNEnaoOuwOoJjkuU_idwDB43mD1bT63p_waU,590
135
+ beswarm/tools/completion.py,sha256=wHEJrdzjuTKQNQZhelSuPnK2YRsGbeUqZ0P6IgT3c10,605
136
136
  beswarm/tools/edit_file.py,sha256=iwWl7a8sTVq4vj0e1ny3H6UGcHfYnxALRGcLuk5hZS8,9155
137
137
  beswarm/tools/planner.py,sha256=lguBCS6kpwNPoXQvqH-WySabVubT82iyWOkJnjt6dXw,1265
138
138
  beswarm/tools/repomap.py,sha256=YsTPq5MXfn_Ds5begcvHDnY_Xp2d4jH-xmWqNMHnNHY,45239
139
139
  beswarm/tools/request_input.py,sha256=gXNAJPOJektMqxJVyzNTFOeMQ7xUkO-wWMYH-r2Rdwk,942
140
140
  beswarm/tools/screenshot.py,sha256=u6t8FCgW5YHJ_Oc4coo8e0F3wTusWE_-H8dFh1rBq9Q,1011
141
- beswarm/tools/search_arxiv.py,sha256=caVIUOzMhFu-r_gVgJZrH2EO9xI5iV_qLAg0b3Ie9Xg,8095
141
+ beswarm/tools/search_arxiv.py,sha256=8naYRvmELQryMIcCCBHebIEzNJ8_YivXamM4fzGG3Dk,10754
142
142
  beswarm/tools/search_web.py,sha256=LhgXOSHL9fwxg5T2AAOV4TTJkcJVLogsfRJW2faPvDE,16147
143
- beswarm/tools/subtasks.py,sha256=isc0bo24vVe3jCWW1wdP7hD5OQymilyka-QR7VSxx78,3652
143
+ beswarm/tools/subtasks.py,sha256=8RmDhpyjDI3vhwfVhh6HQZIv-OZ0mI3e27zS3FnF09E,7881
144
144
  beswarm/tools/worker.py,sha256=auoAEeg8U_Q59dlyM2nv9cAJIWG3PuR8oy7Bp2cM2S0,1993
145
- beswarm-0.2.39.dist-info/METADATA,sha256=GjSazlrJ-HZ8Y78--8EL-8XqBUJAqUUnTb3qXbmDzP8,3878
146
- beswarm-0.2.39.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
147
- beswarm-0.2.39.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
148
- beswarm-0.2.39.dist-info/RECORD,,
145
+ beswarm/tools/write_csv.py,sha256=-r5OghcvjCg00hY0YQbp6u31VIJLrgaqDIvczAFoqDE,1470
146
+ beswarm-0.2.41.dist-info/METADATA,sha256=OBUu8wl3eJH4n5s4lV9NLisFY6LsQBPK8O7zON4Arf4,3878
147
+ beswarm-0.2.41.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
148
+ beswarm-0.2.41.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
149
+ beswarm-0.2.41.dist-info/RECORD,,