beswarm 0.2.73__tar.gz → 0.2.76__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.
Files changed (132) hide show
  1. {beswarm-0.2.73 → beswarm-0.2.76}/PKG-INFO +1 -1
  2. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/agents/planact.py +8 -4
  3. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/response.py +13 -9
  4. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/utils.py +28 -1
  5. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/models/chatgpt.py +19 -1
  6. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm.egg-info/PKG-INFO +1 -1
  7. {beswarm-0.2.73 → beswarm-0.2.76}/pyproject.toml +1 -1
  8. {beswarm-0.2.73 → beswarm-0.2.76}/MANIFEST.in +0 -0
  9. {beswarm-0.2.73 → beswarm-0.2.76}/README.md +0 -0
  10. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/__init__.py +0 -0
  11. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/agents/chatgroup.py +0 -0
  12. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/__init__.py +0 -0
  13. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/__init__.py +0 -0
  14. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/log_config.py +0 -0
  15. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/models.py +0 -0
  16. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/request.py +0 -0
  17. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/test/test_base_api.py +0 -0
  18. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/test/test_geminimask.py +0 -0
  19. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/test/test_image.py +0 -0
  20. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/core/test/test_payload.py +0 -0
  21. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/models/__init__.py +0 -0
  22. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/models/audio.py +0 -0
  23. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/models/base.py +0 -0
  24. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/__init__.py +0 -0
  25. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/arXiv.py +0 -0
  26. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/config.py +0 -0
  27. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/excute_command.py +0 -0
  28. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/get_time.py +0 -0
  29. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/image.py +0 -0
  30. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/list_directory.py +0 -0
  31. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/read_file.py +0 -0
  32. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/read_image.py +0 -0
  33. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/readonly.py +0 -0
  34. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/registry.py +0 -0
  35. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/run_python.py +0 -0
  36. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/websearch.py +0 -0
  37. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/plugins/write_file.py +0 -0
  38. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/utils/__init__.py +0 -0
  39. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/utils/prompt.py +0 -0
  40. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/aient/utils/scripts.py +0 -0
  41. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_Web_crawler.py +0 -0
  42. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_ddg_search.py +0 -0
  43. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_google_search.py +0 -0
  44. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_ollama.py +0 -0
  45. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_plugin.py +0 -0
  46. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_search.py +0 -0
  47. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_url.py +0 -0
  48. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_whisper.py +0 -0
  49. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/aient/test/test_yjh.py +0 -0
  50. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/bemcp/bemcp/__init__.py +0 -0
  51. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/bemcp/bemcp/decorator.py +0 -0
  52. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/bemcp/bemcp/main.py +0 -0
  53. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/bemcp/bemcp/utils.py +0 -0
  54. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/bemcp/test/client.py +0 -0
  55. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/bemcp/test/server.py +0 -0
  56. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/broker.py +0 -0
  57. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/core.py +0 -0
  58. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/knowledge_graph.py +0 -0
  59. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/prompt.py +0 -0
  60. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/README.md +0 -0
  61. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/arduino-tags.scm +0 -0
  62. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/c-tags.scm +0 -0
  63. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/chatito-tags.scm +0 -0
  64. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/commonlisp-tags.scm +0 -0
  65. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/cpp-tags.scm +0 -0
  66. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/csharp-tags.scm +0 -0
  67. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/d-tags.scm +0 -0
  68. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/dart-tags.scm +0 -0
  69. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/elisp-tags.scm +0 -0
  70. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/elixir-tags.scm +0 -0
  71. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/elm-tags.scm +0 -0
  72. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/gleam-tags.scm +0 -0
  73. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/go-tags.scm +0 -0
  74. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/java-tags.scm +0 -0
  75. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/javascript-tags.scm +0 -0
  76. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/lua-tags.scm +0 -0
  77. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/pony-tags.scm +0 -0
  78. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/properties-tags.scm +0 -0
  79. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/python-tags.scm +0 -0
  80. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/r-tags.scm +0 -0
  81. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/racket-tags.scm +0 -0
  82. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/ruby-tags.scm +0 -0
  83. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/rust-tags.scm +0 -0
  84. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/solidity-tags.scm +0 -0
  85. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/swift-tags.scm +0 -0
  86. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-language-pack/udev-tags.scm +0 -0
  87. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/README.md +0 -0
  88. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/c-tags.scm +0 -0
  89. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/c_sharp-tags.scm +0 -0
  90. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/cpp-tags.scm +0 -0
  91. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/dart-tags.scm +0 -0
  92. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/elisp-tags.scm +0 -0
  93. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/elixir-tags.scm +0 -0
  94. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/elm-tags.scm +0 -0
  95. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/go-tags.scm +0 -0
  96. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/hcl-tags.scm +0 -0
  97. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/java-tags.scm +0 -0
  98. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/javascript-tags.scm +0 -0
  99. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/kotlin-tags.scm +0 -0
  100. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/ocaml-tags.scm +0 -0
  101. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/php-tags.scm +0 -0
  102. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/python-tags.scm +0 -0
  103. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/ql-tags.scm +0 -0
  104. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/ruby-tags.scm +0 -0
  105. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/rust-tags.scm +0 -0
  106. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/scala-tags.scm +0 -0
  107. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/queries/tree-sitter-languages/typescript-tags.scm +0 -0
  108. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/taskmanager.py +0 -0
  109. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/__init__.py +0 -0
  110. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/click.py +0 -0
  111. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/completion.py +0 -0
  112. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/edit_file.py +0 -0
  113. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/graph.py +0 -0
  114. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/planner.py +0 -0
  115. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/repomap.py +0 -0
  116. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/request_input.py +0 -0
  117. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/screenshot.py +0 -0
  118. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/search_arxiv.py +0 -0
  119. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/search_web.py +0 -0
  120. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/subtasks.py +0 -0
  121. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/worker.py +0 -0
  122. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/tools/write_csv.py +0 -0
  123. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm/utils.py +0 -0
  124. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm.egg-info/SOURCES.txt +0 -0
  125. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm.egg-info/dependency_links.txt +0 -0
  126. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm.egg-info/requires.txt +0 -0
  127. {beswarm-0.2.73 → beswarm-0.2.76}/beswarm.egg-info/top_level.txt +0 -0
  128. {beswarm-0.2.73 → beswarm-0.2.76}/setup.cfg +0 -0
  129. {beswarm-0.2.73 → beswarm-0.2.76}/test/test_TaskManager.py +0 -0
  130. {beswarm-0.2.73 → beswarm-0.2.76}/test/test_broker.py +0 -0
  131. {beswarm-0.2.73 → beswarm-0.2.76}/test/test_graph.py +0 -0
  132. {beswarm-0.2.73 → beswarm-0.2.76}/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.73
3
+ Version: 0.2.76
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -12,10 +12,10 @@ from typing import List, Dict, Union
12
12
 
13
13
  from ..broker import MessageBroker
14
14
  from ..aient.aient.models import chatgpt
15
- from ..aient.aient.models.chatgpt import ModelNotFoundError, TaskComplete, RetryFailedError
16
15
  from ..aient.aient.plugins import get_function_call_list, registry
17
16
  from ..prompt import worker_system_prompt, instruction_system_prompt
18
17
  from ..utils import extract_xml_content, get_current_screen_image_message, replace_xml_content, register_mcp_tools, setup_logger
18
+ from ..aient.aient.models.chatgpt import ModelNotFoundError, TaskComplete, RetryFailedError, InputTokenCountExceededError, BadRequestError
19
19
 
20
20
  try:
21
21
  from importlib import metadata
@@ -154,11 +154,12 @@ class InstructionAgent(BaseAgent):
154
154
  self.logger.error("❌ Commander retry failed, retrying...")
155
155
  self.broker.publish(message, self.error_topic)
156
156
  return
157
-
158
- if "'status_code': 413" in raw_response or \
159
- "'status_code': 400" in raw_response:
157
+ except InputTokenCountExceededError as e:
160
158
  self.broker.publish({"status": "error", "result": "The request body is too long, please try again."}, self.status_topic)
161
159
  return
160
+ except BadRequestError as e:
161
+ self.broker.publish({"status": "error", "result": "Bad request error!"}, self.status_topic)
162
+ return
162
163
 
163
164
  self.broker.publish({"status": "new_message", "result": "\n🤖 指令智能体:\n" + raw_response}, self.status_topic)
164
165
 
@@ -225,6 +226,9 @@ class WorkerAgent(BaseAgent):
225
226
  except TaskComplete as e:
226
227
  self.broker.publish({"status": "finished", "result": e.completion_message}, self.status_topic)
227
228
  return
229
+ except InputTokenCountExceededError as e:
230
+ self.broker.publish({"status": "error", "result": "The request body is too long, please try again."}, self.status_topic)
231
+ return
228
232
  except RetryFailedError as e:
229
233
  self.logger.error("❌ Worker retry failed, retrying...")
230
234
  self.broker.publish(message, self.error_topic)
@@ -21,13 +21,12 @@ async def check_response(response, error_log):
21
21
  return {"error": f"{error_log} HTTP Error", "status_code": response.status_code, "details": error_json}
22
22
  return None
23
23
 
24
- async def gemini_json_poccess(response_str):
24
+ async def gemini_json_poccess(response_json):
25
25
  promptTokenCount = 0
26
26
  candidatesTokenCount = 0
27
27
  totalTokenCount = 0
28
28
  image_base64 = None
29
29
 
30
- response_json = await asyncio.to_thread(json.loads, response_str)
31
30
  json_data = safe_get(response_json, "candidates", 0, "content", default=None)
32
31
  finishReason = safe_get(response_json, "candidates", 0 , "finishReason", default=None)
33
32
  if finishReason:
@@ -48,7 +47,7 @@ async def gemini_json_poccess(response_str):
48
47
 
49
48
  function_call_name = safe_get(json_data, "functionCall", "name", default=None)
50
49
  function_full_response = safe_get(json_data, "functionCall", "args", default="")
51
- function_full_response = json.dumps(function_full_response) if function_full_response else None
50
+ function_full_response = await asyncio.to_thread(json.dumps, function_full_response) if function_full_response else None
52
51
 
53
52
  blockReason = safe_get(json_data, 0, "promptFeedback", "blockReason", default=None)
54
53
 
@@ -77,7 +76,7 @@ async def fetch_gemini_response_stream(client, url, headers, payload, model, tim
77
76
  if line.startswith("data: "):
78
77
  parts_json = line.lstrip("data: ").strip()
79
78
  try:
80
- await asyncio.to_thread(json.loads, parts_json)
79
+ response_json = await asyncio.to_thread(json.loads, parts_json)
81
80
  except json.JSONDecodeError:
82
81
  logger.error(f"JSON decode error: {parts_json}")
83
82
  continue
@@ -85,12 +84,12 @@ async def fetch_gemini_response_stream(client, url, headers, payload, model, tim
85
84
  parts_json += line
86
85
  parts_json = parts_json.lstrip("[,")
87
86
  try:
88
- await asyncio.to_thread(json.loads, parts_json)
87
+ response_json = await asyncio.to_thread(json.loads, parts_json)
89
88
  except json.JSONDecodeError:
90
89
  continue
91
90
 
92
91
  # https://ai.google.dev/api/generate-content?hl=zh-cn#FinishReason
93
- is_thinking, reasoning_content, content, image_base64, function_call_name, function_full_response, finishReason, blockReason, promptTokenCount, candidatesTokenCount, totalTokenCount = await gemini_json_poccess(parts_json)
92
+ is_thinking, reasoning_content, content, image_base64, function_call_name, function_full_response, finishReason, blockReason, promptTokenCount, candidatesTokenCount, totalTokenCount = await gemini_json_poccess(response_json)
94
93
 
95
94
  if is_thinking:
96
95
  sse_string = await generate_sse_response(timestamp, model, reasoning_content=reasoning_content)
@@ -184,7 +183,7 @@ async def fetch_vertex_claude_response_stream(client, url, headers, payload, mod
184
183
  function_call_id = function_call["id"]
185
184
  sse_string = await generate_sse_response(timestamp, model, content=None, tools_id=function_call_id, function_call_name=function_call_name)
186
185
  yield sse_string
187
- function_full_response = json.dumps(function_call["input"])
186
+ function_full_response = await asyncio.to_thread(json.dumps, function_call["input"])
188
187
  sse_string = await generate_sse_response(timestamp, model, content=None, tools_id=function_call_id, function_call_name=None, function_call_content=function_full_response)
189
188
  yield sse_string
190
189
 
@@ -214,6 +213,9 @@ async def fetch_gpt_response_stream(client, url, headers, payload, timeout):
214
213
  while "\n" in buffer:
215
214
  line, buffer = buffer.split("\n", 1)
216
215
  # logger.info("line: %s", repr(line))
216
+ if line.startswith(": keepalive"):
217
+ yield line + end_of_line
218
+ continue
217
219
  if line and not line.startswith(":") and (result:=line.lstrip("data: ").strip()):
218
220
  if result.strip() == "[DONE]":
219
221
  break
@@ -307,7 +309,8 @@ async def fetch_gpt_response_stream(client, url, headers, payload, timeout):
307
309
  else:
308
310
  if no_stream_content:
309
311
  del line["choices"][0]["message"]
310
- yield "data: " + json.dumps(line).strip() + end_of_line
312
+ json_line = await asyncio.to_thread(json.dumps, line)
313
+ yield "data: " + json_line.strip() + end_of_line
311
314
  yield "data: [DONE]" + end_of_line
312
315
 
313
316
  async def fetch_azure_response_stream(client, url, headers, payload, timeout):
@@ -364,7 +367,8 @@ async def fetch_azure_response_stream(client, url, headers, payload, timeout):
364
367
  else:
365
368
  if no_stream_content:
366
369
  del line["choices"][0]["message"]
367
- yield "data: " + json.dumps(line).strip() + end_of_line
370
+ json_line = await asyncio.to_thread(json.dumps, line)
371
+ yield "data: " + json_line.strip() + end_of_line
368
372
  yield "data: [DONE]" + end_of_line
369
373
 
370
374
  async def fetch_cloudflare_response_stream(client, url, headers, payload, model, timeout):
@@ -243,7 +243,8 @@ def parse_rate_limit(limit_string):
243
243
  'h': 3600, 'hr': 3600, 'hour': 3600,
244
244
  'd': 86400, 'day': 86400,
245
245
  'mo': 2592000, 'month': 2592000,
246
- 'y': 31536000, 'year': 31536000
246
+ 'y': 31536000, 'year': 31536000,
247
+ 'tpr': -1,
247
248
  }
248
249
 
249
250
  # 处理多个限制条件
@@ -377,6 +378,32 @@ class ThreadSafeCircularList:
377
378
  logger.warning(f"All API keys are rate limited!")
378
379
  raise HTTPException(status_code=429, detail="Too many requests")
379
380
 
381
+ async def is_tpr_exceeded(self, model: str = None, tokens: int = 0) -> bool:
382
+ """Checks if the request exceeds the TPR (Tokens Per Request) limit."""
383
+ if not tokens:
384
+ return False
385
+
386
+ async with self.lock:
387
+ rate_limit = None
388
+ model_key = model or "default"
389
+ if model and model_key in self.rate_limits:
390
+ rate_limit = self.rate_limits[model_key]
391
+ else:
392
+ # fuzzy match
393
+ for limit_model in self.rate_limits:
394
+ if limit_model != "default" and model and limit_model in model:
395
+ rate_limit = self.rate_limits[limit_model]
396
+ break
397
+ if rate_limit is None:
398
+ rate_limit = self.rate_limits.get("default", [])
399
+
400
+ for limit_count, limit_period in rate_limit:
401
+ if limit_period == -1: # TPR limit
402
+ if tokens > limit_count:
403
+ # logger.warning(f"API provider for model {model_key} exceeds TPR limit ({tokens}/{limit_count}).")
404
+ return True
405
+ return False
406
+
380
407
  async def is_all_rate_limited(self, model: str = None) -> bool:
381
408
  """检查是否所有的items都被速率限制
382
409
 
@@ -37,10 +37,18 @@ class RateLimitError(Exception):
37
37
  """Custom exception for rate limit (429) errors."""
38
38
  pass
39
39
 
40
+ class BadRequestError(Exception):
41
+ """Custom exception for bad request (400) errors."""
42
+ pass
43
+
40
44
  class HTTPError(Exception):
41
45
  """Custom exception for HTTP 500 errors."""
42
46
  pass
43
47
 
48
+ class InputTokenCountExceededError(Exception):
49
+ """Custom exception for input token count exceeding the maximum."""
50
+ pass
51
+
44
52
  class ConfigurationError(Exception):
45
53
  """Custom exception for configuration errors."""
46
54
  pass
@@ -802,6 +810,10 @@ class chatgpt(BaseLLM):
802
810
  raise ModelNotFoundError(f"Model: {model or self.engine} not found!")
803
811
  if "HTTP Error', 'status_code': 429" in processed_chunk:
804
812
  raise RateLimitError(f"Rate limit exceeded for model: {model or self.engine}")
813
+ if "HTTP Error', 'status_code': 413" in processed_chunk:
814
+ raise InputTokenCountExceededError(processed_chunk)
815
+ if "HTTP Error', 'status_code': 400" in processed_chunk:
816
+ raise BadRequestError(f"Bad Request: {processed_chunk}")
805
817
  if "HTTP Error', 'status_code': " in processed_chunk:
806
818
  raise HTTPError(f"HTTP Error: {processed_chunk}")
807
819
  yield processed_chunk
@@ -814,7 +826,7 @@ class chatgpt(BaseLLM):
814
826
  return # Stop iteration
815
827
  except httpx.RemoteProtocolError:
816
828
  continue
817
- except httpx.ReadError:
829
+ except httpx.ReadError as e:
818
830
  self.logger.warning(f"{e}, retrying...")
819
831
  continue
820
832
  except APITimeoutError:
@@ -826,6 +838,12 @@ class chatgpt(BaseLLM):
826
838
  except RateLimitError as e:
827
839
  self.logger.warning(f"{e}, retrying...")
828
840
  continue
841
+ except InputTokenCountExceededError as e:
842
+ self.logger.error(f"The request body is too long: {e}")
843
+ raise
844
+ except BadRequestError as e:
845
+ self.logger.error(f"Bad request error: {e}")
846
+ raise
829
847
  except ValidationError as e:
830
848
  self.logger.warning(f"Validation failed: {e}. Retrying with corrective prompt.")
831
849
  need_done_prompt = [
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.2.73
3
+ Version: 0.2.76
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.73"
3
+ version = "0.2.76"
4
4
  description = "MAS"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
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