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

@@ -1,6 +1,7 @@
1
1
  import uuid
2
2
  import networkx as nx
3
3
  from pathlib import Path
4
+ from .aient.src.aient.utils.scripts import unescape_html
4
5
 
5
6
  class KnowledgeGraphManager:
6
7
  """
@@ -48,7 +49,7 @@ class KnowledgeGraphManager:
48
49
  def _create_new_graph(self):
49
50
  """创建一个带有根节点的新图谱并保存。"""
50
51
  self.graph = nx.DiGraph()
51
- self.graph.add_node("root", name=".", description="知识图谱根节点")
52
+ self.graph.add_node("root", name=".", description="知识图谱根节点", tags="")
52
53
  self._save_graph()
53
54
 
54
55
  def set_publish_topic(self, publish_topic):
@@ -68,6 +69,7 @@ class KnowledgeGraphManager:
68
69
  if path is None or not path.strip() or path.strip() in ['.', '/']:
69
70
  return "root"
70
71
 
72
+ path = unescape_html(path)
71
73
  segments = [s for s in path.strip('/').split('/') if s and s != '.']
72
74
  current_node_id = "root"
73
75
 
@@ -102,8 +104,11 @@ class KnowledgeGraphManager:
102
104
 
103
105
  return current_node_id
104
106
 
105
- def add_node(self, parent_path: str, node_name: str, description: str = "") -> str:
107
+ def add_node(self, parent_path: str, node_name: str, description: str = "", tags: list[str] = None) -> str:
106
108
  """在指定父节点下添加一个新节点。"""
109
+ parent_path = unescape_html(parent_path)
110
+ node_name = unescape_html(node_name)
111
+ description = unescape_html(description)
107
112
  if not node_name.strip():
108
113
  return "❌ 错误:节点名称不能为空。"
109
114
  if '/' in node_name:
@@ -118,13 +123,60 @@ class KnowledgeGraphManager:
118
123
  return f"❌ 错误:在 '{parent_path}' 下已存在名为 '{node_name}' 的节点。"
119
124
 
120
125
  new_node_id = str(uuid.uuid4())
121
- self.graph.add_node(new_node_id, name=node_name, description=description)
126
+ # 将标签列表转换为内部存储的字符串格式
127
+ tags_str = ",".join(sorted(list(set(filter(None, tags or [])))))
128
+ self.graph.add_node(new_node_id, name=node_name, description=description, tags=tags_str)
122
129
  self.graph.add_edge(parent_id, new_node_id)
123
130
  self._save_graph()
124
131
  return f"✅ 成功在 '{parent_path}' 下添加节点 '{node_name}'。"
125
132
 
133
+ def _get_tags(self, node_id: str) -> list[str]:
134
+ """获取节点的标签列表。"""
135
+ tags_str = self.graph.nodes[node_id].get('tags', '')
136
+ return tags_str.split(',') if tags_str else []
137
+
138
+ def _set_tags(self, node_id: str, tags: list[str]):
139
+ """设置节点的标签列表。"""
140
+ # 移除重复项并排序
141
+ unique_tags = sorted(list(set(filter(None, tags))))
142
+ self.graph.nodes[node_id]['tags'] = ",".join(unique_tags)
143
+
144
+ def add_tags_to_node(self, node_path: str, tags_to_add: list[str]) -> str:
145
+ """向指定节点添加一个或多个标签。"""
146
+ node_path = unescape_html(node_path)
147
+ node_id = self._get_node_id_by_path(node_path)
148
+ if node_id is None:
149
+ return f"❌ 错误:路径 '{node_path}' 不存在。"
150
+
151
+ current_tags = self._get_tags(node_id)
152
+ current_tags.extend(tags_to_add)
153
+ self._set_tags(node_id, current_tags)
154
+ self._save_graph()
155
+ return f"✅ 成功向节点 '{node_path}' 添加标签: {' '.join([f'#{t}' for t in tags_to_add])}"
156
+
157
+ def remove_tags_from_node(self, node_path: str, tags_to_remove: list[str]) -> str:
158
+ """从指定节点移除一个或多个标签。"""
159
+ node_path = unescape_html(node_path)
160
+ node_id = self._get_node_id_by_path(node_path)
161
+ if node_id is None:
162
+ return f"❌ 错误:路径 '{node_path}' 不存在。"
163
+
164
+ current_tags = self._get_tags(node_id)
165
+ if not current_tags:
166
+ return f"ℹ️ 节点 '{node_path}' 没有任何标签可供移除。"
167
+
168
+ new_tags = [tag for tag in current_tags if tag not in tags_to_remove]
169
+
170
+ if len(new_tags) == len(current_tags):
171
+ return f"ℹ️ 在节点 '{node_path}' 上未找到指定的标签: {' '.join([f'#{t}' for t in tags_to_remove])}"
172
+
173
+ self._set_tags(node_id, new_tags)
174
+ self._save_graph()
175
+ return f"✅ 成功从节点 '{node_path}' 移除标签。"
176
+
126
177
  def delete_node(self, node_path: str) -> str:
127
178
  """删除一个节点及其所有子孙节点。"""
179
+ node_path = unescape_html(node_path)
128
180
  if node_path is None or node_path.strip() in ['.', '/']:
129
181
  return "❌ 错误:不能删除根节点。"
130
182
 
@@ -141,6 +193,8 @@ class KnowledgeGraphManager:
141
193
 
142
194
  def rename_node(self, node_path: str, new_name: str) -> str:
143
195
  """重命名一个节点。"""
196
+ node_path = unescape_html(node_path)
197
+ new_name = unescape_html(new_name)
144
198
  if not new_name.strip():
145
199
  return "❌ 错误:新名称不能为空。"
146
200
  if '/' in new_name:
@@ -163,6 +217,8 @@ class KnowledgeGraphManager:
163
217
 
164
218
  def move_node(self, source_path: str, target_parent_path: str) -> str:
165
219
  """将一个节点移动到另一个父节点下。"""
220
+ source_path = unescape_html(source_path)
221
+ target_parent_path = unescape_html(target_parent_path)
166
222
  source_id = self._get_node_id_by_path(source_path)
167
223
  if source_id is None:
168
224
  return f"❌ 错误:源路径 '{source_path}' 不存在。"
@@ -187,6 +243,30 @@ class KnowledgeGraphManager:
187
243
  self._save_graph()
188
244
  return f"✅ 成功将节点 '{source_path}' 移动到 '{target_parent_path}' 下。"
189
245
 
246
+ def get_node_details(self, node_path: str) -> str:
247
+ """获取指定路径节点的所有详细信息。"""
248
+ node_path = unescape_html(node_path)
249
+ node_id = self._get_node_id_by_path(node_path)
250
+ if node_id is None:
251
+ return f"❌ 错误:路径 '{node_path}' 不存在。"
252
+
253
+ node_data = self.graph.nodes[node_id]
254
+ description = node_data.get('description', '无描述。')
255
+ tags = self._get_tags(node_id)
256
+
257
+ # 路径就用用户输入的,因为这才是用户识别它的方式
258
+ details = [f"节点: {node_path}"]
259
+ details.append(f"描述: {description}")
260
+
261
+ if tags:
262
+ # 格式化标签为 '#技术细节, #激活函数'
263
+ formatted_tags = " ".join([f"#{t}" for t in tags])
264
+ details.append(f"标签: {formatted_tags}")
265
+ else:
266
+ details.append("标签: 无")
267
+
268
+ return "\n".join(details)
269
+
190
270
  def render_tree(self) -> str:
191
271
  """渲染整个知识图谱为树状结构的文本。"""
192
272
  if not self.graph or "root" not in self.graph:
@@ -204,6 +284,13 @@ class KnowledgeGraphManager:
204
284
  is_last = (i == len(children) - 1)
205
285
  connector = "└── " if is_last else "├── "
206
286
  node_name = self.graph.nodes[child_id].get('name', '[Unnamed Node]')
287
+
288
+ # 显示标签,过滤掉以'source'开头的标签
289
+ tags = self._get_tags(child_id)
290
+ display_tags = [t for t in tags if not t.startswith('source')]
291
+ if display_tags:
292
+ node_name += f" {' '.join([f'#{t}' for t in display_tags])}"
293
+
207
294
  tree_lines.append(f"{prefix}{connector}{node_name}")
208
295
  new_prefix = prefix + " " if is_last else prefix + "│ "
209
- self._build_tree_string_recursive(child_id, new_prefix, tree_lines)
296
+ self._build_tree_string_recursive(child_id, new_prefix, tree_lines)
beswarm/tools/__init__.py CHANGED
@@ -4,7 +4,16 @@ from .completion import task_complete
4
4
  from .search_arxiv import search_arxiv
5
5
  from .repomap import get_code_repo_map
6
6
  from .write_csv import append_row_to_csv
7
- from .graph import add_knowledge_node, delete_knowledge_node, rename_knowledge_node, move_knowledge_node, get_knowledge_graph_tree
7
+ from .graph import (
8
+ get_node_details,
9
+ add_knowledge_node,
10
+ delete_knowledge_node,
11
+ rename_knowledge_node,
12
+ move_knowledge_node,
13
+ get_knowledge_graph_tree,
14
+ add_tags_to_knowledge_node,
15
+ remove_tags_from_knowledge_node,
16
+ )
8
17
  from .request_input import request_admin_input
9
18
  from .screenshot import save_screenshot_to_file
10
19
  from .worker import worker, worker_gen, chatgroup
@@ -49,11 +58,14 @@ __all__ = [
49
58
  "list_directory",
50
59
  "get_task_result",
51
60
  "get_url_content",
61
+ "get_node_details",
52
62
  "add_knowledge_node",
53
63
  "move_knowledge_node",
54
64
  "delete_knowledge_node",
55
65
  "rename_knowledge_node",
56
66
  "get_knowledge_graph_tree",
67
+ "add_tags_to_knowledge_node",
68
+ "remove_tags_from_knowledge_node",
57
69
  "append_row_to_csv",
58
70
  "set_readonly_path",
59
71
  "get_code_repo_map",
beswarm/tools/graph.py CHANGED
@@ -1,8 +1,11 @@
1
- from ..aient.src.aient.plugins import register_tool
1
+ import ast
2
+ from typing import List
3
+
2
4
  from ..core import kgm
5
+ from ..aient.src.aient.plugins import register_tool
3
6
 
4
7
  @register_tool()
5
- def add_knowledge_node(parent_path: str, node_name: str, description: str = "") -> str:
8
+ def add_knowledge_node(parent_path: str, node_name: str, description: str = "", tags: List[str] = None) -> str:
6
9
  """
7
10
  在知识图谱的指定父路径下添加一个新节点。
8
11
 
@@ -10,11 +13,64 @@ def add_knowledge_node(parent_path: str, node_name: str, description: str = "")
10
13
  parent_path (str): 父节点的路径。路径由'/'分隔,例如 'a/b'。根节点路径为 '.' 或 '/'。
11
14
  node_name (str): 新节点的名称。名称中不能包含'/'字符。
12
15
  description (str, optional): 节点的可选描述信息。默认为空字符串。
16
+ tags (List[str], optional): 节点的标签列表。默认为 None。
13
17
 
14
18
  Returns:
15
19
  str: 操作结果的描述信息,例如成功或失败的原因。
16
20
  """
17
- return kgm.add_node(parent_path, node_name, description)
21
+ if tags:
22
+ if "[" not in tags:
23
+ if "," not in tags:
24
+ tags = f"['{tags}']"
25
+ else:
26
+ tags = f"{tags.split(',')}"
27
+ tags = ast.literal_eval(tags) if isinstance(tags, str) else tags
28
+ tags = [tag.strip().lstrip("#") for tag in tags]
29
+ return kgm.add_node(parent_path, node_name, description, tags)
30
+
31
+ @register_tool()
32
+ def add_tags_to_knowledge_node(node_path: str, tags: List[str]) -> str:
33
+ """
34
+ 向知识图谱中的指定节点添加一个或多个标签。
35
+
36
+ Args:
37
+ node_path (str): 要添加标签的节点的完整路径。
38
+ tags (List[str]): 要添加的标签列表。
39
+
40
+ Returns:
41
+ str: 操作结果的描述信息。
42
+ """
43
+ if "[" not in tags:
44
+ if "," not in tags:
45
+ tags = f"['{tags}']"
46
+ else:
47
+ tags = f"{tags.split(',')}"
48
+
49
+ tags = ast.literal_eval(tags) if isinstance(tags, str) else tags
50
+ tags = [tag.strip().lstrip("#") for tag in tags]
51
+ return kgm.add_tags_to_node(node_path, tags)
52
+
53
+ @register_tool()
54
+ def remove_tags_from_knowledge_node(node_path: str, tags: List[str]) -> str:
55
+ """
56
+ 从知识图谱中的指定节点移除一个或多个标签。
57
+
58
+ Args:
59
+ node_path (str): 要移除标签的节点的完整路径。
60
+ tags (List[str]): 要移除的标签列表。
61
+
62
+ Returns:
63
+ str: 操作结果的描述信息。
64
+ """
65
+ if "[" not in tags:
66
+ if "," not in tags:
67
+ tags = f"['{tags}']"
68
+ else:
69
+ tags = f"{tags.split(',')}"
70
+
71
+ tags = ast.literal_eval(tags) if isinstance(tags, str) else tags
72
+ tags = [tag.strip().lstrip("#") for tag in tags]
73
+ return kgm.remove_tags_from_node(node_path, tags)
18
74
 
19
75
  @register_tool()
20
76
  def delete_knowledge_node(node_path: str) -> str:
@@ -71,3 +127,19 @@ def get_knowledge_graph_tree() -> str:
71
127
  str: 表示整个知识图谱的、格式化的树状结构字符串。
72
128
  """
73
129
  return "<knowledge_graph_tree>" + kgm.render_tree() + "</knowledge_graph_tree>"
130
+
131
+ @register_tool()
132
+ def get_node_details(node_path: str) -> str:
133
+ """
134
+ 获取知识图谱中指定路径节点的所有详细信息。可以显示 get_knowledge_graph_tree 隐藏的信息。
135
+
136
+ 这个工具用于深入查看单个节点的具体内容,包括其描述和所有标签。
137
+ 它与 `get_knowledge_graph_tree`(提供全局视图)互补。
138
+
139
+ Args:
140
+ node_path (str): 要查询的节点的完整路径。
141
+
142
+ Returns:
143
+ str: 包含节点详细信息的、格式化的文本字符串。
144
+ """
145
+ return kgm.get_node_details(node_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.2.48
3
+ Version: 0.2.50
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,7 +1,7 @@
1
1
  beswarm/__init__.py,sha256=HZjUOJtZR5QhMuDbq-wukQQn1VrBusNWai_ysGo-VVI,20
2
2
  beswarm/broker.py,sha256=64Y-djrKYaZfBQ8obwHOmr921QgZeu9BtScZWaYLfDo,9887
3
3
  beswarm/core.py,sha256=htssaaeIBZ_yOqvX9VtANoVWaZHt_7oWcxyDI1z0paQ,310
4
- beswarm/knowledge_graph.py,sha256=Q2hhXL2RXnAM8vvxstYetch5wX7ghTM5S7FnORSxCG0,9205
4
+ beswarm/knowledge_graph.py,sha256=PY3gVHuIT7zEp9qhIw9uDYz6koRUPa0RYd2REOwWjRc,13084
5
5
  beswarm/prompt.py,sha256=n0a1a6NThIxAYSkisg1sEKjvz2w0tozpKL4BIplaAkI,32286
6
6
  beswarm/taskmanager.py,sha256=xczsnehCaOAI3SRE8wUxhzmt6i6G7ynndSWS_bAZn3k,12192
7
7
  beswarm/utils.py,sha256=S9jEtht0hTZbjZ2Hk24p4Ip41R69BogOkYS6fgPKY2Y,8219
@@ -131,11 +131,11 @@ beswarm/queries/tree-sitter-languages/ruby-tags.scm,sha256=vIidsCeE2A0vdFN18yXKq
131
131
  beswarm/queries/tree-sitter-languages/rust-tags.scm,sha256=9ljM1nzhfPs_ZTRw7cr2P9ToOyhGcKkCoN4_HPXSWi4,1451
132
132
  beswarm/queries/tree-sitter-languages/scala-tags.scm,sha256=UxQjz80JIrrJ7Pm56uUnQyThfmQNvwk7aQzPNypB-Ao,1761
133
133
  beswarm/queries/tree-sitter-languages/typescript-tags.scm,sha256=OMdCeedPiA24ky82DpgTMKXK_l2ySTuF2zrQ2fJAi9E,1253
134
- beswarm/tools/__init__.py,sha256=fhJSEaYcfgMTW_nzUqQiyX5RLBhE-gxs8u4PpFquOdg,1868
134
+ beswarm/tools/__init__.py,sha256=5ZJeCEau1OVVOVBMv5E0DTGERsgknSxSLX8o4B1WR8k,2081
135
135
  beswarm/tools/click.py,sha256=7g6x1X7ffTInGWp7112KS-MAQ5-8wa1Ze2sIipUIbjc,20884
136
136
  beswarm/tools/completion.py,sha256=wHEJrdzjuTKQNQZhelSuPnK2YRsGbeUqZ0P6IgT3c10,605
137
137
  beswarm/tools/edit_file.py,sha256=iwWl7a8sTVq4vj0e1ny3H6UGcHfYnxALRGcLuk5hZS8,9155
138
- beswarm/tools/graph.py,sha256=-Lyhi-AsJNKQ5p9BJk6mzARd1-IDhdLyKmNAVN5PdUE,2703
138
+ beswarm/tools/graph.py,sha256=f0OmaB1UI9rdYU5KNxOUINPBvXhLo5pdznrCKNpQ3nM,5088
139
139
  beswarm/tools/planner.py,sha256=lguBCS6kpwNPoXQvqH-WySabVubT82iyWOkJnjt6dXw,1265
140
140
  beswarm/tools/repomap.py,sha256=YsTPq5MXfn_Ds5begcvHDnY_Xp2d4jH-xmWqNMHnNHY,45239
141
141
  beswarm/tools/request_input.py,sha256=gXNAJPOJektMqxJVyzNTFOeMQ7xUkO-wWMYH-r2Rdwk,942
@@ -145,7 +145,7 @@ beswarm/tools/search_web.py,sha256=LhgXOSHL9fwxg5T2AAOV4TTJkcJVLogsfRJW2faPvDE,1
145
145
  beswarm/tools/subtasks.py,sha256=zZmRCjDocbvrU8MvZvpDWpQCKNntDJ123ByBiS8pRko,9889
146
146
  beswarm/tools/worker.py,sha256=-tcLGrdLPZYxc1z66iQIB1VH7RWcR-5CgVWuDIQJBCQ,2013
147
147
  beswarm/tools/write_csv.py,sha256=-r5OghcvjCg00hY0YQbp6u31VIJLrgaqDIvczAFoqDE,1470
148
- beswarm-0.2.48.dist-info/METADATA,sha256=x4Nf2GnW7tPwtMAWDVu3tTMWj1aJkM-6gwFPwG5Ga8Q,3878
149
- beswarm-0.2.48.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
150
- beswarm-0.2.48.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
151
- beswarm-0.2.48.dist-info/RECORD,,
148
+ beswarm-0.2.50.dist-info/METADATA,sha256=GjMlSOekWJWwnLPekTnpAoxjnPC9tmkAHou-EIUIG5k,3878
149
+ beswarm-0.2.50.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
150
+ beswarm-0.2.50.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
151
+ beswarm-0.2.50.dist-info/RECORD,,