beswarm 0.2.26__tar.gz → 0.2.28__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 (150) hide show
  1. {beswarm-0.2.26 → beswarm-0.2.28}/PKG-INFO +1 -1
  2. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/__init__.py +7 -1
  3. beswarm-0.2.28/beswarm/tools/completion.py +17 -0
  4. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/taskmanager.py +143 -4
  5. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/worker.py +32 -50
  6. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm.egg-info/PKG-INFO +1 -1
  7. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm.egg-info/SOURCES.txt +1 -0
  8. {beswarm-0.2.26 → beswarm-0.2.28}/pyproject.toml +2 -2
  9. {beswarm-0.2.26 → beswarm-0.2.28}/MANIFEST.in +0 -0
  10. {beswarm-0.2.26 → beswarm-0.2.28}/README.md +0 -0
  11. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/__init__.py +0 -0
  12. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/main.py +0 -0
  13. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/setup.py +0 -0
  14. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/__init__.py +0 -0
  15. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/__init__.py +0 -0
  16. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/log_config.py +0 -0
  17. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/models.py +0 -0
  18. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/request.py +0 -0
  19. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/response.py +0 -0
  20. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/test/test_base_api.py +0 -0
  21. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/test/test_geminimask.py +0 -0
  22. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/test/test_image.py +0 -0
  23. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/test/test_payload.py +0 -0
  24. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/core/utils.py +0 -0
  25. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/__init__.py +0 -0
  26. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/audio.py +0 -0
  27. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/base.py +0 -0
  28. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/chatgpt.py +0 -0
  29. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/claude.py +0 -0
  30. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/duckduckgo.py +0 -0
  31. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/gemini.py +0 -0
  32. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/groq.py +0 -0
  33. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/models/vertex.py +0 -0
  34. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/__init__.py +0 -0
  35. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/arXiv.py +0 -0
  36. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/config.py +0 -0
  37. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/excute_command.py +0 -0
  38. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/get_time.py +0 -0
  39. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/image.py +0 -0
  40. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/list_directory.py +0 -0
  41. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/read_file.py +0 -0
  42. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/read_image.py +0 -0
  43. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/readonly.py +0 -0
  44. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/registry.py +0 -0
  45. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/run_python.py +0 -0
  46. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/websearch.py +0 -0
  47. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/plugins/write_file.py +0 -0
  48. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/utils/__init__.py +0 -0
  49. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/utils/prompt.py +0 -0
  50. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/src/aient/utils/scripts.py +0 -0
  51. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/chatgpt.py +0 -0
  52. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/claude.py +0 -0
  53. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test.py +0 -0
  54. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_API.py +0 -0
  55. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_Deepbricks.py +0 -0
  56. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_Web_crawler.py +0 -0
  57. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_aiwaves.py +0 -0
  58. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_aiwaves_arxiv.py +0 -0
  59. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_ask_gemini.py +0 -0
  60. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_class.py +0 -0
  61. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_claude.py +0 -0
  62. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_claude_zh_char.py +0 -0
  63. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_ddg_search.py +0 -0
  64. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_download_pdf.py +0 -0
  65. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_gemini.py +0 -0
  66. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_get_token_dict.py +0 -0
  67. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_google_search.py +0 -0
  68. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_jieba.py +0 -0
  69. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_json.py +0 -0
  70. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_logging.py +0 -0
  71. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_ollama.py +0 -0
  72. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_plugin.py +0 -0
  73. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_py_run.py +0 -0
  74. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_requests.py +0 -0
  75. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_search.py +0 -0
  76. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_tikitoken.py +0 -0
  77. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_token.py +0 -0
  78. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_url.py +0 -0
  79. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_whisper.py +0 -0
  80. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_wildcard.py +0 -0
  81. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/aient/test/test_yjh.py +0 -0
  82. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/bemcp/bemcp/__init__.py +0 -0
  83. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/bemcp/bemcp/decorator.py +0 -0
  84. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/bemcp/bemcp/main.py +0 -0
  85. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/bemcp/bemcp/utils.py +0 -0
  86. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/bemcp/test/client.py +0 -0
  87. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/bemcp/test/server.py +0 -0
  88. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/prompt.py +0 -0
  89. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/README.md +0 -0
  90. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
  91. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/c-tags.scm +0 -0
  92. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
  93. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
  94. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
  95. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
  96. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/d-tags.scm +0 -0
  97. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
  98. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
  99. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
  100. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
  101. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
  102. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/go-tags.scm +0 -0
  103. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/java-tags.scm +0 -0
  104. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
  105. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
  106. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
  107. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
  108. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/python-tags.scm +0 -0
  109. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/r-tags.scm +0 -0
  110. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
  111. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
  112. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
  113. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
  114. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
  115. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
  116. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/README.md +0 -0
  117. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/c-tags.scm +0 -0
  118. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
  119. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/cpp-tags.scm +0 -0
  120. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/dart-tags.scm +0 -0
  121. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/elisp-tags.scm +0 -0
  122. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/elixir-tags.scm +0 -0
  123. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/elm-tags.scm +0 -0
  124. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/go-tags.scm +0 -0
  125. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/hcl-tags.scm +0 -0
  126. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/java-tags.scm +0 -0
  127. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/javascript-tags.scm +0 -0
  128. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
  129. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
  130. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/php-tags.scm +0 -0
  131. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/python-tags.scm +0 -0
  132. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/ql-tags.scm +0 -0
  133. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/ruby-tags.scm +0 -0
  134. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/rust-tags.scm +0 -0
  135. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/scala-tags.scm +0 -0
  136. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/queries/tree-sitter-languages/typescript-tags.scm +0 -0
  137. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/click.py +0 -0
  138. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/edit_file.py +0 -0
  139. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/planner.py +0 -0
  140. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/repomap.py +0 -0
  141. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/request_input.py +0 -0
  142. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/screenshot.py +0 -0
  143. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/search_arxiv.py +0 -0
  144. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/tools/search_web.py +0 -0
  145. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm/utils.py +0 -0
  146. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm.egg-info/dependency_links.txt +0 -0
  147. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm.egg-info/requires.txt +0 -0
  148. {beswarm-0.2.26 → beswarm-0.2.28}/beswarm.egg-info/top_level.txt +0 -0
  149. {beswarm-0.2.26 → beswarm-0.2.28}/setup.cfg +0 -0
  150. {beswarm-0.2.26 → beswarm-0.2.28}/test/test_TaskManager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.2.26
3
+ Version: 0.2.28
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,5 +1,5 @@
1
1
  from .edit_file import edit_file
2
- from .worker import worker, worker_gen, create_task, get_task_result
2
+ from .worker import worker, worker_gen
3
3
  from .screenshot import save_screenshot_to_file
4
4
  from .request_input import request_admin_input
5
5
 
@@ -7,6 +7,9 @@ from .search_arxiv import search_arxiv
7
7
  from .repomap import get_code_repo_map
8
8
  from .click import find_and_click_element, scroll_screen
9
9
  from .search_web import search_web
10
+ from .taskmanager import create_task, resume_task, get_all_tasks_status, get_task_result
11
+ from .completion import task_complete
12
+
10
13
  #显式导入 aient.plugins 中的所需内容
11
14
  from ..aient.src.aient.plugins import (
12
15
  excute_command,
@@ -50,5 +53,8 @@ __all__ = [
50
53
  "set_readonly_path",
51
54
  "request_admin_input",
52
55
  "create_task",
56
+ "resume_task",
57
+ "get_all_tasks_status",
53
58
  "get_task_result",
59
+ "task_complete",
54
60
  ]
@@ -0,0 +1,17 @@
1
+ from ..aient.src.aient.plugins import register_tool
2
+
3
+ @register_tool()
4
+ def task_complete(message: str) -> str:
5
+ """
6
+ 当任务完成时,调用此工具以返回最终结果。
7
+
8
+ 这个工具接收一个表示任务完成信息的字符串,并将其直接返回。
9
+ 它标志着一个任务的成功结束,并将最终的输出传递给用户或调用者。
10
+
11
+ Args:
12
+ message (str): 任务完成的信息或最终结果。
13
+
14
+ Returns:
15
+ str: 传入的任务完成信息。
16
+ """
17
+ return "<task_complete_message>" + message + "</task_complete_message>"
@@ -1,9 +1,12 @@
1
- import os
1
+ import ast
2
+ import json
2
3
  import uuid
3
4
  import asyncio
4
5
  from enum import Enum
5
6
  from pathlib import Path
6
7
 
8
+ from ..aient.src.aient.plugins import register_tool, registry
9
+
7
10
  class TaskStatus(Enum):
8
11
  """任务状态枚举"""
9
12
  PENDING = "PENDING"
@@ -19,7 +22,49 @@ class TaskManager:
19
22
  def __init__(self):
20
23
  self.tasks = {} # 使用字典来存储任务,key是task_id, value是task对象
21
24
  self.results_queue = asyncio.Queue()
22
- self.root_path = Path(os.getcwd())
25
+ self.root_path = None
26
+ self.tasks_cache = {}
27
+
28
+ def set_root_path(self, root_path):
29
+ if self.root_path:
30
+ return
31
+ self.root_path = Path(root_path)
32
+ self.cache_dir = self.root_path / ".beswarm"
33
+ self.task_cache_file = self.cache_dir / "tasks.json"
34
+ self.task_cache_file.touch(exist_ok=True)
35
+ self.read_tasks_cache()
36
+ self.set_task_cache("root_path", str(self.root_path))
37
+
38
+ def set_task_cache(self, *keys_and_value):
39
+ """
40
+ 设置可嵌套的任务缓存。
41
+ 接受无限个键和一个值,例如 set_task_cache('a', 'b', 'c', value)
42
+ 会转换为 tasks_cache['a']['b']['c'] = value
43
+ """
44
+ if len(keys_and_value) < 2:
45
+ return # 至少需要一个键和一个值
46
+
47
+ keys = keys_and_value[:-1]
48
+ value = keys_and_value[-1]
49
+
50
+ d = self.tasks_cache
51
+ # 遍历到倒数第二个键,确保路径存在
52
+ for key in keys[:-1]:
53
+ d = d.setdefault(key, {})
54
+
55
+ # 在最后一个键上设置值
56
+ d[keys[-1]] = value
57
+ self.save_tasks_cache()
58
+
59
+ def save_tasks_cache(self):
60
+ self.task_cache_file.write_text(json.dumps(self.tasks_cache, ensure_ascii=False, indent=4), encoding="utf-8")
61
+
62
+ def read_tasks_cache(self):
63
+ content = self.task_cache_file.read_text(encoding="utf-8")
64
+ try:
65
+ self.tasks_cache = json.loads(content) if content else {}
66
+ except json.JSONDecodeError:
67
+ raise ValueError("任务缓存文件格式错误")
23
68
 
24
69
  def create_tasks(self, task_coro, tasks_params):
25
70
  """
@@ -37,8 +82,27 @@ class TaskManager:
37
82
  coro = task_coro(**args)
38
83
  task_id = self.create_task(coro)
39
84
  task_ids.append(task_id)
85
+ self.set_task_cache(task_id, "args", args)
86
+ self.set_task_cache(task_id, "status", TaskStatus.RUNNING.value)
40
87
  return task_ids
41
88
 
89
+ def resume_task(self, task_id, task_coro, args):
90
+ """
91
+ 恢复一个任务。
92
+ """
93
+ task = self.tasks_cache.get(task_id)
94
+ if not task:
95
+ return TaskStatus.NOT_FOUND
96
+
97
+ coro = task_coro(**args)
98
+ task_id = self.create_task(coro)
99
+ self.set_task_cache(task_id, "args", args)
100
+ self.set_task_cache(task_id, "status", TaskStatus.RUNNING.value)
101
+ print(f"任务已恢复: ID={task_id}, Name={task_id}")
102
+ print(f"args: {args}")
103
+ print(f"self.tasks_cache: {json.dumps(self.tasks_cache, ensure_ascii=False, indent=4)}")
104
+ return task_id
105
+
42
106
  def create_task(self, coro):
43
107
  """
44
108
  创建并注册一个新任务。
@@ -108,14 +172,19 @@ class TaskManager:
108
172
  self.results_queue.put_nowait(
109
173
  (task_id, TaskStatus.DONE, task.result())
110
174
  )
175
+ self.set_task_cache(task_id, "status", TaskStatus.DONE.value)
176
+ self.set_task_cache(task_id, "result", task.result())
111
177
  except asyncio.CancelledError:
112
178
  self.results_queue.put_nowait(
113
179
  (task_id, TaskStatus.CANCELLED, None)
114
180
  )
181
+ self.set_task_cache(task_id, "status", TaskStatus.CANCELLED.value)
115
182
  except Exception as e:
116
183
  self.results_queue.put_nowait(
117
184
  (task_id, TaskStatus.ERROR, e)
118
185
  )
186
+ self.set_task_cache(task_id, "status", TaskStatus.ERROR.value)
187
+ self.set_task_cache(task_id, "result", str(e))
119
188
 
120
189
  async def get_next_result(self):
121
190
  """
@@ -146,8 +215,78 @@ class TaskManager:
146
215
  # 如果任务ID不存在,则返回-1
147
216
  return -1
148
217
 
149
- def set_root_path(self, root_path):
150
- self.root_path = Path(root_path)
218
+
219
+ task_manager = TaskManager()
220
+
221
+ worker_fun = registry.tools["worker"]
222
+
223
+ @register_tool()
224
+ def create_task(goal, tools, work_dir):
225
+ """
226
+ 启动一个子任务来自动完成指定的任务目标 (`goal`)。
227
+
228
+ 这个子任务接收一个清晰的任务描述、一组可供调用的工具 (`tools`),以及一个工作目录 (`work_dir`)。
229
+ 它会结合可用的工具,自主规划并逐步执行必要的操作,直到最终完成指定的任务目标。
230
+ 核心功能是根据输入的目标,驱动整个任务执行流程。
231
+ 子任务下上文为空,因此需要细致的背景信息。
232
+
233
+ Args:
234
+ goal (str): 需要完成的具体任务目标描述。子任务将围绕此目标进行工作。必须清晰、具体。必须包含背景信息,完成指标等。写清楚什么时候算任务完成,同时交代清楚任务的背景信息,这个背景信息可以是需要读取的文件等一切有助于完成任务的信息。
235
+ tools (list[str]): 一个包含可用工具函数对象的列表。子任务在执行任务时可能会调用这些工具来与环境交互(例如读写文件、执行命令等)。
236
+ work_dir (str): 工作目录的绝对路径。子任务将在此目录上下文中执行操作。子任务的工作目录位置在主任务的工作目录的子目录。
237
+
238
+ Returns:
239
+ str: 当任务成功完成时,返回字符串 "任务已完成"。
240
+ """
241
+ tasks_params = [
242
+ {"goal": goal, "tools": ast.literal_eval(tools), "work_dir": work_dir, "cache_messages": True}
243
+ ]
244
+ task_ids = task_manager.create_tasks(worker_fun, tasks_params)
245
+ return task_ids
246
+
247
+ @register_tool()
248
+ def resume_task(task_id, goal):
249
+ """
250
+ 恢复一个子任务。
251
+ """
252
+ if task_id not in task_manager.tasks_cache:
253
+ return f"任务 {task_id} 不存在"
254
+ tasks_params = task_manager.tasks_cache[task_id]["args"]
255
+ tasks_params["goal"] = goal
256
+ tasks_params["cache_messages"] = True
257
+ task_id = task_manager.resume_task(task_id, worker_fun, tasks_params)
258
+ return f"任务 {task_id} 已恢复"
259
+
260
+ @register_tool()
261
+ def get_all_tasks_status():
262
+ """
263
+ 获取所有任务的状态。
264
+ 子任务状态会持久化到磁盘,因此即使历史记录为空,之前的子任务仍然存在。
265
+
266
+ Returns:
267
+ str: 所有任务的状态。每个任务的id,状态,结果。
268
+ """
269
+ return task_manager.tasks_cache
270
+
271
+ @register_tool()
272
+ async def get_task_result():
273
+ """
274
+ 等待并获取子任务的执行结果。如果需要等待子任务完成,请使用这个工具。一旦有任务完成,会自动获取结果。如果调用时没有任务完成,会等待直到有任务完成。
275
+
276
+ Returns:
277
+ str: 子任务的执行结果。
278
+ """
279
+ task_id, status, result = await task_manager.get_next_result()
280
+
281
+ unfinished_tasks = [task_id for task_id, task in task_manager.tasks_cache.items() if task_id != "root_path" and task.get("status") != "DONE"]
282
+ text = "".join([
283
+ f"Task ID: {task_id}\n",
284
+ f"Status: {status.value}\n",
285
+ f"Result: {result}\n\n",
286
+ f"There are {len(unfinished_tasks)} unfinished tasks, unfinished task ids: {unfinished_tasks}" if unfinished_tasks else "All tasks are finished.",
287
+ ])
288
+
289
+ return text
151
290
 
152
291
  async def main():
153
292
  manager = TaskManager()
@@ -1,7 +1,6 @@
1
1
  import os
2
2
  import re
3
3
  import sys
4
- import ast
5
4
  import copy
6
5
  import json
7
6
  import difflib
@@ -27,50 +26,14 @@ from ..aient.src.aient.plugins import register_tool, get_function_call_list, reg
27
26
  from ..prompt import worker_system_prompt, instruction_system_prompt
28
27
  from ..utils import extract_xml_content, get_current_screen_image_message, replace_xml_content, register_mcp_tools
29
28
  from ..bemcp.bemcp import MCPClient, convert_tool_format, MCPManager
30
- from .taskmanager import TaskManager
31
29
 
32
30
  manager = MCPManager()
33
- task_manager = TaskManager()
34
-
35
- @register_tool()
36
- def create_task(goal, tools, work_dir):
37
- """
38
- 启动一个子任务来自动完成指定的任务目标 (`goal`)。
39
-
40
- 这个子任务接收一个清晰的任务描述、一组可供调用的工具 (`tools`),以及一个工作目录 (`work_dir`)。
41
- 它会结合可用的工具,自主规划并逐步执行必要的操作,直到最终完成指定的任务目标。
42
- 核心功能是根据输入的目标,驱动整个任务执行流程。
43
- 子任务下上文为空,因此需要细致的背景信息。
44
-
45
- Args:
46
- goal (str): 需要完成的具体任务目标描述。子任务将围绕此目标进行工作。必须清晰、具体。必须包含背景信息,完成指标等。写清楚什么时候算任务完成,同时交代清楚任务的背景信息,这个背景信息可以是需要读取的文件等一切有助于完成任务的信息。
47
- tools (list[str]): 一个包含可用工具函数对象的列表。子任务在执行任务时可能会调用这些工具来与环境交互(例如读写文件、执行命令等)。
48
- work_dir (str): 工作目录的绝对路径。子任务将在此目录上下文中执行操作。子任务的工作目录位置在主任务的工作目录的子目录。
49
-
50
- Returns:
51
- str: 当任务成功完成时,返回字符串 "任务已完成"。
52
- """
53
- tasks_params = [
54
- {"goal": goal, "tools": ast.literal_eval(tools), "work_dir": work_dir, "cache_messages": True}
55
- ]
56
- task_ids = task_manager.create_tasks(worker, tasks_params)
57
- return task_ids
58
-
59
- @register_tool()
60
- async def get_task_result():
61
- """
62
- 等待并获取子任务的执行结果。
63
-
64
- Returns:
65
- str: 子任务的执行结果。
66
- """
67
- task_id, status, result = await task_manager.get_next_result()
68
- return result
69
31
 
70
32
  @register_tool()
71
33
  async def worker(goal, tools, work_dir, cache_messages=None):
72
34
  cache_dir = Path(work_dir) / ".beswarm"
73
35
  cache_dir.mkdir(parents=True, exist_ok=True)
36
+ task_manager.set_root_path(work_dir)
74
37
  cache_file = cache_dir / "work_agent_conversation_history.json"
75
38
  if not cache_file.exists():
76
39
  cache_file.write_text("[]", encoding="utf-8")
@@ -101,6 +64,8 @@ async def worker(goal, tools, work_dir, cache_messages=None):
101
64
  tools += mcp_tools_name
102
65
 
103
66
  tools = [item for item in tools if not isinstance(item, dict)]
67
+ if "task_complete" not in tools:
68
+ tools.append("task_complete")
104
69
 
105
70
  tools_json = [value for _, value in get_function_call_list(tools).items()]
106
71
  work_agent_system_prompt = worker_system_prompt.format(
@@ -157,7 +122,7 @@ async def worker(goal, tools, work_dir, cache_messages=None):
157
122
  f"任务目标: {goal}\n\n",
158
123
  f"任务目标新变化:\n{goal_diff}\n\n" if goal_diff else "",
159
124
  "在 tag <work_agent_conversation_start>...</work_agent_conversation_end> 之前的对话历史都是工作智能体的对话历史。\n\n",
160
- "根据以上对话历史和目标,请生成下一步指令。如果任务已完成,请回复'任务已完成'。\n\n",
125
+ "根据以上对话历史和目标,请生成下一步指令。如果任务已完成,指示工作智能体调用task_complete工具。\n\n",
161
126
  ])
162
127
  if last_instruction and 'fetch_gpt_response_stream HTTP Error' not in last_instruction:
163
128
  instruction_prompt = (
@@ -168,6 +133,11 @@ async def worker(goal, tools, work_dir, cache_messages=None):
168
133
  # 让指令agent分析对话历史并生成新指令
169
134
  instruction_agent = chatgpt(**instruction_agent_config)
170
135
  conversation_history = copy.deepcopy(work_agent.conversation["default"])
136
+ if len(conversation_history) > 1 and conversation_history[-2]["role"] == "user" \
137
+ and "<task_complete_message>" in conversation_history[-2]["content"]:
138
+ task_complete_message = extract_xml_content(conversation_history[-2]["content"], "task_complete_message")
139
+ # del work_agent.conversation["default"][-4:]
140
+ return "<task_complete_message>" + task_complete_message + "</task_complete_message>"
171
141
 
172
142
  cache_file.write_text(json.dumps(conversation_history, ensure_ascii=False, indent=4), encoding="utf-8")
173
143
 
@@ -206,8 +176,7 @@ async def worker(goal, tools, work_dir, cache_messages=None):
206
176
  print(f"任务结束时间: {end_time.strftime('%Y-%m-%d %H:%M:%S')}")
207
177
  print(f"总用时: {total_time}")
208
178
  raise Exception(f"The request body is too long, please try again.")
209
- if "任务已完成" == next_instruction.strip():
210
- break
179
+
211
180
  last_instruction = next_instruction
212
181
  next_instruction = extract_xml_content(next_instruction, "instructions")
213
182
  if not next_instruction:
@@ -235,18 +204,19 @@ async def worker(goal, tools, work_dir, cache_messages=None):
235
204
  return next_instruction
236
205
 
237
206
  need_instruction = True
207
+ result = None
238
208
  while True:
239
209
  next_instruction = ''
240
210
  if need_instruction:
241
211
  next_instruction = await instruction_agent_task()
242
212
 
243
213
  # 检查任务是否完成
244
- if "任务已完成" in next_instruction and len(next_instruction) < 10:
214
+ if "<task_complete_message>" in next_instruction:
245
215
  if finish_flag == 0:
246
216
  finish_flag = 1
247
217
  continue
248
218
  elif finish_flag == 1:
249
- print("\n✅ 任务已完成!")
219
+ result = extract_xml_content(next_instruction, "task_complete_message")
250
220
  break
251
221
  else:
252
222
  finish_flag = 0
@@ -262,15 +232,17 @@ async def worker(goal, tools, work_dir, cache_messages=None):
262
232
 
263
233
  end_time = datetime.now()
264
234
  total_time = end_time - start_time
235
+ print("\n✅ 任务已完成:", result)
265
236
  print(f"\n任务开始时间: {start_time.strftime('%Y-%m-%d %H:%M:%S')}")
266
237
  print(f"任务结束时间: {end_time.strftime('%Y-%m-%d %H:%M:%S')}")
267
238
  print(f"总用时: {total_time}")
268
239
  await manager.cleanup()
269
- return "任务已完成"
240
+ return result
270
241
 
271
242
  async def worker_gen(goal, tools, work_dir, cache_messages=None):
272
243
  cache_dir = Path(work_dir) / ".beswarm"
273
244
  cache_dir.mkdir(parents=True, exist_ok=True)
245
+ task_manager.set_root_path(work_dir)
274
246
  cache_file = cache_dir / "work_agent_conversation_history.json"
275
247
  if not cache_file.exists():
276
248
  cache_file.write_text("[]", encoding="utf-8")
@@ -301,6 +273,8 @@ async def worker_gen(goal, tools, work_dir, cache_messages=None):
301
273
  tools += mcp_tools_name
302
274
 
303
275
  tools = [item for item in tools if not isinstance(item, dict)]
276
+ if "task_complete" not in tools:
277
+ tools.append("task_complete")
304
278
 
305
279
  tools_json = [value for _, value in get_function_call_list(tools).items()]
306
280
  work_agent_system_prompt = worker_system_prompt.format(
@@ -357,7 +331,7 @@ async def worker_gen(goal, tools, work_dir, cache_messages=None):
357
331
  f"任务目标: {goal}\n\n",
358
332
  f"任务目标新变化:\n{goal_diff}\n\n" if goal_diff else "",
359
333
  "在 tag <work_agent_conversation_start>...</work_agent_conversation_end> 之前的对话历史都是工作智能体的对话历史。\n\n",
360
- "根据以上对话历史和目标,请生成下一步指令。如果任务已完成,请回复'任务已完成'。\n\n",
334
+ "根据以上对话历史和目标,请生成下一步指令。如果任务已完成,指示工作智能体调用task_complete工具。\n\n",
361
335
  ])
362
336
  if last_instruction and 'fetch_gpt_response_stream HTTP Error' not in last_instruction:
363
337
  instruction_prompt = (
@@ -368,6 +342,11 @@ async def worker_gen(goal, tools, work_dir, cache_messages=None):
368
342
  # 让指令agent分析对话历史并生成新指令
369
343
  instruction_agent = chatgpt(**instruction_agent_config)
370
344
  conversation_history = copy.deepcopy(work_agent.conversation["default"])
345
+ if len(conversation_history) > 1 and conversation_history[-2]["role"] == "user" \
346
+ and "<task_complete_message>" in conversation_history[-2]["content"]:
347
+ task_complete_message = extract_xml_content(conversation_history[-2]["content"], "task_complete_message")
348
+ # del work_agent.conversation["default"][-4:]
349
+ return "<task_complete_message>" + task_complete_message + "</task_complete_message>"
371
350
 
372
351
  cache_file.write_text(json.dumps(conversation_history, ensure_ascii=False, indent=4), encoding="utf-8")
373
352
 
@@ -406,8 +385,7 @@ async def worker_gen(goal, tools, work_dir, cache_messages=None):
406
385
  print(f"任务结束时间: {end_time.strftime('%Y-%m-%d %H:%M:%S')}")
407
386
  print(f"总用时: {total_time}")
408
387
  raise Exception(f"The request body is too long, please try again.")
409
- if "任务已完成" == next_instruction.strip():
410
- break
388
+
411
389
  last_instruction = next_instruction
412
390
  next_instruction = extract_xml_content(next_instruction, "instructions")
413
391
  if not next_instruction:
@@ -435,6 +413,7 @@ async def worker_gen(goal, tools, work_dir, cache_messages=None):
435
413
  return next_instruction
436
414
 
437
415
  need_instruction = True
416
+ result = None
438
417
  while True:
439
418
  next_instruction = ''
440
419
  if need_instruction:
@@ -443,12 +422,12 @@ async def worker_gen(goal, tools, work_dir, cache_messages=None):
443
422
  yield {"user": next_instruction}
444
423
 
445
424
  # 检查任务是否完成
446
- if "任务已完成" in next_instruction and len(next_instruction) < 10:
425
+ if "<task_complete_message>" in next_instruction:
447
426
  if finish_flag == 0:
448
427
  finish_flag = 1
449
428
  continue
450
429
  elif finish_flag == 1:
451
- print("\n✅ 任务已完成!")
430
+ result = extract_xml_content(next_instruction, "task_complete_message")
452
431
  break
453
432
  else:
454
433
  finish_flag = 0
@@ -465,7 +444,10 @@ async def worker_gen(goal, tools, work_dir, cache_messages=None):
465
444
 
466
445
  end_time = datetime.now()
467
446
  total_time = end_time - start_time
447
+ print("\n✅ 任务已完成:", result)
468
448
  print(f"\n任务开始时间: {start_time.strftime('%Y-%m-%d %H:%M:%S')}")
469
449
  print(f"任务结束时间: {end_time.strftime('%Y-%m-%d %H:%M:%S')}")
470
450
  print(f"总用时: {total_time}")
471
- await manager.cleanup()
451
+ await manager.cleanup()
452
+
453
+ from .taskmanager import task_manager
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.2.26
3
+ Version: 0.2.28
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -135,6 +135,7 @@ beswarm/queries/tree-sitter-languages/scala-tags.scm
135
135
  beswarm/queries/tree-sitter-languages/typescript-tags.scm
136
136
  beswarm/tools/__init__.py
137
137
  beswarm/tools/click.py
138
+ beswarm/tools/completion.py
138
139
  beswarm/tools/edit_file.py
139
140
  beswarm/tools/planner.py
140
141
  beswarm/tools/repomap.py
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "beswarm"
3
- version = "0.2.26"
3
+ version = "0.2.28"
4
4
  description = "MAS"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -37,4 +37,4 @@ search = [
37
37
 
38
38
  [tool.setuptools.packages.find]
39
39
  where = ["."]
40
- include = ["beswarm*"]
40
+ include = ["beswarm*"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes