beswarm 0.2.48__tar.gz → 0.2.50__tar.gz

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.

Files changed (161) hide show
  1. {beswarm-0.2.48 → beswarm-0.2.50}/PKG-INFO +1 -1
  2. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/knowledge_graph.py +91 -4
  3. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/__init__.py +13 -1
  4. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/graph.py +75 -3
  5. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm.egg-info/PKG-INFO +1 -1
  6. {beswarm-0.2.48 → beswarm-0.2.50}/pyproject.toml +1 -1
  7. {beswarm-0.2.48 → beswarm-0.2.50}/test/test_graph.py +86 -10
  8. {beswarm-0.2.48 → beswarm-0.2.50}/MANIFEST.in +0 -0
  9. {beswarm-0.2.48 → beswarm-0.2.50}/README.md +0 -0
  10. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/__init__.py +0 -0
  11. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/agents/chatgroup.py +0 -0
  12. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/agents/planact.py +0 -0
  13. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/main.py +0 -0
  14. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/setup.py +0 -0
  15. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/__init__.py +0 -0
  16. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/__init__.py +0 -0
  17. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/log_config.py +0 -0
  18. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/models.py +0 -0
  19. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/request.py +0 -0
  20. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/response.py +0 -0
  21. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/test/test_base_api.py +0 -0
  22. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/test/test_geminimask.py +0 -0
  23. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/test/test_image.py +0 -0
  24. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/test/test_payload.py +0 -0
  25. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/core/utils.py +0 -0
  26. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/__init__.py +0 -0
  27. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/audio.py +0 -0
  28. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/base.py +0 -0
  29. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/chatgpt.py +0 -0
  30. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/claude.py +0 -0
  31. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/duckduckgo.py +0 -0
  32. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/gemini.py +0 -0
  33. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/groq.py +0 -0
  34. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/models/vertex.py +0 -0
  35. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/__init__.py +0 -0
  36. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/arXiv.py +0 -0
  37. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/config.py +0 -0
  38. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/excute_command.py +0 -0
  39. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/get_time.py +0 -0
  40. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/image.py +0 -0
  41. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/list_directory.py +0 -0
  42. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/read_file.py +0 -0
  43. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/read_image.py +0 -0
  44. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/readonly.py +0 -0
  45. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/registry.py +0 -0
  46. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/run_python.py +0 -0
  47. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/websearch.py +0 -0
  48. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/plugins/write_file.py +0 -0
  49. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/utils/__init__.py +0 -0
  50. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/utils/prompt.py +0 -0
  51. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/src/aient/utils/scripts.py +0 -0
  52. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/chatgpt.py +0 -0
  53. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/claude.py +0 -0
  54. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test.py +0 -0
  55. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_API.py +0 -0
  56. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_Deepbricks.py +0 -0
  57. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_Web_crawler.py +0 -0
  58. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_aiwaves.py +0 -0
  59. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_aiwaves_arxiv.py +0 -0
  60. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_ask_gemini.py +0 -0
  61. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_class.py +0 -0
  62. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_claude.py +0 -0
  63. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_claude_zh_char.py +0 -0
  64. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_ddg_search.py +0 -0
  65. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_download_pdf.py +0 -0
  66. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_gemini.py +0 -0
  67. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_get_token_dict.py +0 -0
  68. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_google_search.py +0 -0
  69. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_jieba.py +0 -0
  70. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_json.py +0 -0
  71. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_logging.py +0 -0
  72. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_ollama.py +0 -0
  73. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_plugin.py +0 -0
  74. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_py_run.py +0 -0
  75. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_requests.py +0 -0
  76. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_search.py +0 -0
  77. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_tikitoken.py +0 -0
  78. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_token.py +0 -0
  79. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_url.py +0 -0
  80. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_whisper.py +0 -0
  81. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_wildcard.py +0 -0
  82. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/aient/test/test_yjh.py +0 -0
  83. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/bemcp/bemcp/__init__.py +0 -0
  84. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/bemcp/bemcp/decorator.py +0 -0
  85. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/bemcp/bemcp/main.py +0 -0
  86. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/bemcp/bemcp/utils.py +0 -0
  87. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/bemcp/test/client.py +0 -0
  88. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/bemcp/test/server.py +0 -0
  89. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/broker.py +0 -0
  90. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/core.py +0 -0
  91. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/prompt.py +0 -0
  92. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/README.md +0 -0
  93. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
  94. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/c-tags.scm +0 -0
  95. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
  96. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
  97. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
  98. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
  99. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/d-tags.scm +0 -0
  100. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
  101. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
  102. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
  103. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
  104. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
  105. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/go-tags.scm +0 -0
  106. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/java-tags.scm +0 -0
  107. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
  108. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
  109. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
  110. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
  111. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/python-tags.scm +0 -0
  112. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/r-tags.scm +0 -0
  113. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
  114. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
  115. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
  116. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
  117. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
  118. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
  119. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/README.md +0 -0
  120. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/c-tags.scm +0 -0
  121. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
  122. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/cpp-tags.scm +0 -0
  123. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/dart-tags.scm +0 -0
  124. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/elisp-tags.scm +0 -0
  125. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/elixir-tags.scm +0 -0
  126. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/elm-tags.scm +0 -0
  127. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/go-tags.scm +0 -0
  128. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/hcl-tags.scm +0 -0
  129. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/java-tags.scm +0 -0
  130. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/javascript-tags.scm +0 -0
  131. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
  132. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
  133. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/php-tags.scm +0 -0
  134. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/python-tags.scm +0 -0
  135. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/ql-tags.scm +0 -0
  136. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/ruby-tags.scm +0 -0
  137. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/rust-tags.scm +0 -0
  138. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/scala-tags.scm +0 -0
  139. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/queries/tree-sitter-languages/typescript-tags.scm +0 -0
  140. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/taskmanager.py +0 -0
  141. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/click.py +0 -0
  142. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/completion.py +0 -0
  143. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/edit_file.py +0 -0
  144. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/planner.py +0 -0
  145. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/repomap.py +0 -0
  146. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/request_input.py +0 -0
  147. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/screenshot.py +0 -0
  148. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/search_arxiv.py +0 -0
  149. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/search_web.py +0 -0
  150. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/subtasks.py +0 -0
  151. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/worker.py +0 -0
  152. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/tools/write_csv.py +0 -0
  153. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm/utils.py +0 -0
  154. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm.egg-info/SOURCES.txt +0 -0
  155. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm.egg-info/dependency_links.txt +0 -0
  156. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm.egg-info/requires.txt +0 -0
  157. {beswarm-0.2.48 → beswarm-0.2.50}/beswarm.egg-info/top_level.txt +0 -0
  158. {beswarm-0.2.48 → beswarm-0.2.50}/setup.cfg +0 -0
  159. {beswarm-0.2.48 → beswarm-0.2.50}/test/test_TaskManager.py +0 -0
  160. {beswarm-0.2.48 → beswarm-0.2.50}/test/test_broker.py +0 -0
  161. {beswarm-0.2.48 → beswarm-0.2.50}/test/test_new_TaskManager.py +0 -0
@@ -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,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)
@@ -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",
@@ -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,6 +1,6 @@
1
1
  [project]
2
2
  name = "beswarm"
3
- version = "0.2.48"
3
+ version = "0.2.50"
4
4
  description = "MAS"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -44,7 +44,7 @@ class KnowledgeGraphManager:
44
44
  def _create_new_graph(self):
45
45
  """创建一个带有根节点的新图谱。"""
46
46
  self.graph = nx.DiGraph()
47
- self.graph.add_node("root", name=".", description="知识图谱根节点")
47
+ self.graph.add_node("root", name=".", description="知识图谱根节点", tags="")
48
48
 
49
49
  def _save_graph(self):
50
50
  """将当前图的状态保存到文件。"""
@@ -73,7 +73,7 @@ class KnowledgeGraphManager:
73
73
  return None
74
74
  return current_node_id
75
75
 
76
- def add_node(self, parent_path: str, node_name: str, description: str = "") -> str:
76
+ def add_node(self, parent_path: str, node_name: str, description: str = "", tags: list[str] = None) -> str:
77
77
  """在指定父节点下添加一个新节点。"""
78
78
  if not node_name.strip():
79
79
  return "❌ 错误:节点名称不能为空。"
@@ -89,12 +89,54 @@ class KnowledgeGraphManager:
89
89
  return f"❌ 错误:在 '{parent_path}' 下已存在名为 '{node_name}' 的节点。"
90
90
 
91
91
  new_node_id = str(uuid.uuid4())
92
- self.graph.add_node(new_node_id, name=node_name, description=description)
92
+ tags_str = ",".join(sorted(list(set(filter(None, tags or [])))))
93
+ self.graph.add_node(new_node_id, name=node_name, description=description, tags=tags_str)
93
94
  self.graph.add_edge(parent_id, new_node_id)
94
95
 
95
96
  self._save_graph()
96
97
  return f"✅ 成功在 '{parent_path}' 下添加节点 '{node_name}'。"
97
98
 
99
+ def _get_tags(self, node_id: str) -> list[str]:
100
+ """获取节点的标签列表。"""
101
+ tags_str = self.graph.nodes[node_id].get('tags', '')
102
+ return tags_str.split(',') if tags_str else []
103
+
104
+ def _set_tags(self, node_id: str, tags: list[str]):
105
+ """设置节点的标签列表。"""
106
+ unique_tags = sorted(list(set(filter(None, tags))))
107
+ self.graph.nodes[node_id]['tags'] = ",".join(unique_tags)
108
+
109
+ def add_tags_to_node(self, node_path: str, tags_to_add: list[str]) -> str:
110
+ """向指定节点添加一个或多个标签。"""
111
+ node_id = self._get_node_id_by_path(node_path)
112
+ if node_id is None:
113
+ return f"❌ 错误:路径 '{node_path}' 不存在。"
114
+
115
+ current_tags = self._get_tags(node_id)
116
+ current_tags.extend(tags_to_add)
117
+ self._set_tags(node_id, current_tags)
118
+ self._save_graph()
119
+ return f"✅ 成功向节点 '{node_path}' 添加标签: {', '.join(tags_to_add)}。"
120
+
121
+ def remove_tags_from_node(self, node_path: str, tags_to_remove: list[str]) -> str:
122
+ """从指定节点移除一个或多个标签。"""
123
+ node_id = self._get_node_id_by_path(node_path)
124
+ if node_id is None:
125
+ return f"❌ 错误:路径 '{node_path}' 不存在。"
126
+
127
+ current_tags = self._get_tags(node_id)
128
+ if not current_tags:
129
+ return f"ℹ️ 节点 '{node_path}' 没有任何标签可供移除。"
130
+
131
+ new_tags = [tag for tag in current_tags if tag not in tags_to_remove]
132
+
133
+ if len(new_tags) == len(current_tags):
134
+ return f"ℹ️ 在节点 '{node_path}' 上未找到指定的标签: {', '.join(tags_to_remove)}。"
135
+
136
+ self._set_tags(node_id, new_tags)
137
+ self._save_graph()
138
+ return f"✅ 成功从节点 '{node_path}' 移除标签。"
139
+
98
140
  def delete_node(self, node_path: str) -> str:
99
141
  """删除一个节点及其所有子孙节点。"""
100
142
  if node_path is None or node_path.strip() in ['.', '/']:
@@ -161,17 +203,17 @@ class KnowledgeGraphManager:
161
203
  self._save_graph()
162
204
  return f"✅ 成功将节点 '{source_path}' 移动到 '{target_parent_path}' 下。"
163
205
 
164
- def render_tree(self) -> str:
206
+ def render_tree(self, show_source_tags=False) -> str:
165
207
  """渲染整个知识图谱为树状结构的文本。"""
166
208
  if not self.graph or "root" not in self.graph:
167
209
  return "图谱为空或未正确初始化。"
168
210
 
169
211
  tree_lines = [self.graph.nodes["root"]["name"]]
170
212
  # 调用递归函数来构建树
171
- self._build_tree_string_recursive("root", "", tree_lines)
213
+ self._build_tree_string_recursive("root", "", tree_lines, show_source_tags)
172
214
  return "\n".join(tree_lines)
173
215
 
174
- def _build_tree_string_recursive(self, parent_id, prefix, tree_lines):
216
+ def _build_tree_string_recursive(self, parent_id, prefix, tree_lines, show_source_tags=False):
175
217
  """递归辅助函数,用于构建树状图字符串。"""
176
218
  children = sorted(list(self.graph.successors(parent_id)), key=lambda n: self.graph.nodes[n]['name'])
177
219
 
@@ -180,6 +222,17 @@ class KnowledgeGraphManager:
180
222
  is_last = (i == num_children - 1)
181
223
  connector = "└── " if is_last else "├── "
182
224
  node_name = self.graph.nodes[child_id].get('name', '[Unnamed Node]')
225
+
226
+ # 显示标签,过滤掉以'source'开头的标签
227
+ tags = self._get_tags(child_id)
228
+ if show_source_tags:
229
+ display_tags = tags
230
+ else:
231
+ display_tags = [t for t in tags if not t.startswith('source')]
232
+
233
+ if display_tags:
234
+ node_name += f" {' '.join([f'#{t}' for t in display_tags])}"
235
+
183
236
  tree_lines.append(f"{prefix}{connector}{node_name}")
184
237
 
185
238
  new_prefix = prefix + " " if is_last else prefix + "│ "
@@ -195,7 +248,10 @@ def print_menu():
195
248
  print(f"{colors.FAIL}3. ❌ 删除节点{colors.ENDC}")
196
249
  print(f"{colors.OKBLUE}4. ✏️ 重命名节点{colors.ENDC}")
197
250
  print(f"{colors.OKBLUE}5. ➡️ 移动节点{colors.ENDC}")
198
- print(f"{colors.WARNING}6. 🗑️ 删除图谱文件并重置{colors.ENDC}")
251
+ print(f"{colors.OKCYAN}6. 🏷️ 添加标签{colors.ENDC}")
252
+ print(f"{colors.OKCYAN}7. 🗑️ 移除标签{colors.ENDC}")
253
+ print(f"{colors.OKBLUE}8. ℹ️ 查看节点详细信息{colors.ENDC}")
254
+ print(f"{colors.WARNING}9. 💥 删除图谱文件并重置{colors.ENDC}")
199
255
  print("0. 退出")
200
256
  print("-"*50)
201
257
 
@@ -215,7 +271,9 @@ def main_test_loop():
215
271
  parent_path = input("请输入父节点路径 (例如 'a/b', 根节点为'.'): ")
216
272
  node_name = input("请输入新节点名称: ")
217
273
  description = input("请输入节点描述 (可选): ")
218
- result = kgm.add_node(parent_path, node_name, description)
274
+ tags_str = input("请输入标签, 以逗号分隔 (可选): ")
275
+ tags = [tag.strip() for tag in tags_str.split(',') if tag.strip()]
276
+ result = kgm.add_node(parent_path, node_name, description, tags)
219
277
  print(f"\n{result}")
220
278
  elif choice == '3':
221
279
  node_path = input("请输入要删除的节点路径 (例如 'a/b'): ")
@@ -232,6 +290,24 @@ def main_test_loop():
232
290
  result = kgm.move_node(source_path, target_parent_path)
233
291
  print(f"\n{result}")
234
292
  elif choice == '6':
293
+ node_path = input("请输入要添加标签的节点路径: ")
294
+ tags_str = input("请输入要添加的标签 (以逗号分隔): ")
295
+ tags_to_add = [tag.strip() for tag in tags_str.split(',') if tag.strip()]
296
+ result = kgm.add_tags_to_node(node_path, tags_to_add)
297
+ print(f"\n{result}")
298
+ elif choice == '7':
299
+ node_path = input("请输入要移除标签的节点路径: ")
300
+ tags_str = input("请输入要移除的标签 (以逗号分隔): ")
301
+ tags_to_remove = [tag.strip() for tag in tags_str.split(',') if tag.strip()]
302
+ result = kgm.remove_tags_from_node(node_path, tags_to_remove)
303
+ print(f"\n{result}")
304
+ elif choice == '8':
305
+ node_path = input("请输入要查看详情的节点路径: ")
306
+ details = kgm.get_node_details(node_path)
307
+ print("\n--- 节点详细信息 ---")
308
+ print(details)
309
+ print("------------------------")
310
+ elif choice == '9':
235
311
  if kgm.storage_path.exists():
236
312
  confirm = input(f"⚠️ 确定要删除 '{kgm.storage_path}' 并重置吗? (y/n): ").lower()
237
313
  if confirm == 'y':
@@ -246,9 +322,9 @@ def main_test_loop():
246
322
  print("退出程序。")
247
323
  break
248
324
  else:
249
- print("无效输入,请输入0-6之间的数字。")
325
+ print("无效输入,请输入0-9之间的数字。")
250
326
 
251
327
  input("\n按回车键继续...")
252
328
 
253
329
  if __name__ == "__main__":
254
- main_test_loop()
330
+ main_test_loop()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes