beswarm 0.3.13__py3-none-any.whl → 0.3.14__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.
@@ -423,8 +423,16 @@ class Message(ABC):
423
423
  processed_items.append(Images(url=image_url))
424
424
  else:
425
425
  raise ValueError(f"Unsupported item type in list: {item_type}")
426
+ elif isinstance(item, dict):
427
+ item_type = item.get('type')
428
+ if item_type == 'image_url':
429
+ image_url = item.get('image_url', {}).get('url')
430
+ if image_url:
431
+ processed_items.append(Images(url=image_url))
432
+ else:
433
+ raise ValueError(f"Unsupported dict item type: {item_type}")
426
434
  else:
427
- raise TypeError(f"Unsupported item type: {type(item)}. Must be str, ContextProvider, or list.")
435
+ raise TypeError(f"Unsupported item type: {type(item)}. Must be str, ContextProvider, list, or dict.")
428
436
  self._items: List[ContextProvider] = processed_items
429
437
  self._parent_messages: Optional['Messages'] = None
430
438
 
@@ -1884,6 +1884,32 @@ Files: {Files(visible=True, name="files")}
1884
1884
  if os.path.exists(non_existent_file):
1885
1885
  os.remove(non_existent_file)
1886
1886
 
1887
+ async def test_auto_convert_image_dict_to_image_provider(self):
1888
+ """测试 UserMessage 是否能自动转换 image_url 字典为 Images provider"""
1889
+ base64_image_data = "/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAABAAEDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKKKAP/2Q=="
1890
+ image_dict = {
1891
+ 'type': 'image_url',
1892
+ 'image_url': {
1893
+ 'url': f'data:image/jpeg;base64,{base64_image_data}'
1894
+ }
1895
+ }
1896
+
1897
+ # This is the functionality we are testing.
1898
+ # The UserMessage should be able to take this dictionary directly.
1899
+ message = UserMessage(image_dict)
1900
+
1901
+ # 1. Verify that the message contains exactly one provider.
1902
+ self.assertEqual(len(message.provider()), 1)
1903
+
1904
+ # 2. Verify that the provider is an instance of the Images class.
1905
+ image_provider = message.provider()[0]
1906
+ self.assertIsInstance(image_provider, Images)
1907
+
1908
+ # 3. Verify that the content of the Images provider is correct.
1909
+ rendered = await message.render_latest()
1910
+ self.assertEqual(rendered['content'][0]['image_url']['url'], image_dict['image_url']['url'])
1911
+
1912
+
1887
1913
  # ==============================================================================
1888
1914
  # 6. 演示
1889
1915
  # ==============================================================================
@@ -295,7 +295,7 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
295
295
  if key == request.model:
296
296
  for k, v in value.items():
297
297
  payload[k] = v
298
- elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key:
298
+ elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key and " " not in key:
299
299
  payload[key] = value
300
300
 
301
301
  return url, headers, payload
@@ -591,7 +591,7 @@ async def get_vertex_gemini_payload(request, engine, provider, api_key=None):
591
591
  if key == request.model:
592
592
  for k, v in value.items():
593
593
  payload[k] = v
594
- elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key:
594
+ elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key and " " not in key:
595
595
  payload[key] = value
596
596
 
597
597
  return url, headers, payload
@@ -1116,6 +1116,9 @@ async def get_gpt_payload(request, engine, provider, api_key=None):
1116
1116
  if "temperature" in payload:
1117
1117
  payload.pop("temperature")
1118
1118
 
1119
+ if "v1/responses" in url:
1120
+ payload.pop("stream_options", None)
1121
+
1119
1122
  # 代码生成/数学解题  0.0
1120
1123
  # 数据抽取/分析 1.0
1121
1124
  # 通用对话 1.3
@@ -1149,7 +1152,7 @@ async def get_gpt_payload(request, engine, provider, api_key=None):
1149
1152
  if key == request.model:
1150
1153
  for k, v in value.items():
1151
1154
  payload[k] = v
1152
- elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key:
1155
+ elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key and " " not in key:
1153
1156
  payload[key] = value
1154
1157
 
1155
1158
  return url, headers, payload
@@ -1247,7 +1250,7 @@ async def get_azure_payload(request, engine, provider, api_key=None):
1247
1250
  if key == request.model:
1248
1251
  for k, v in value.items():
1249
1252
  payload[k] = v
1250
- elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key:
1253
+ elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key and " " not in key:
1251
1254
  payload[key] = value
1252
1255
 
1253
1256
  return url, headers, payload
@@ -1367,7 +1370,7 @@ async def get_azure_databricks_payload(request, engine, provider, api_key=None):
1367
1370
  if key == request.model:
1368
1371
  for k, v in value.items():
1369
1372
  payload[k] = v
1370
- elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key:
1373
+ elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key and " " not in key:
1371
1374
  payload[key] = value
1372
1375
 
1373
1376
  return url, headers, payload
@@ -1454,7 +1457,7 @@ async def get_openrouter_payload(request, engine, provider, api_key=None):
1454
1457
  if key == request.model:
1455
1458
  for k, v in value.items():
1456
1459
  payload[k] = v
1457
- elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key:
1460
+ elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key and " " not in key:
1458
1461
  payload[key] = value
1459
1462
 
1460
1463
  return url, headers, payload
@@ -1820,7 +1823,7 @@ async def get_claude_payload(request, engine, provider, api_key=None):
1820
1823
  if key == request.model:
1821
1824
  for k, v in value.items():
1822
1825
  payload[k] = v
1823
- elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key:
1826
+ elif all(_model not in request.model.lower() for _model in model_dict.keys()) and "-" not in key and " " not in key:
1824
1827
  payload[key] = value
1825
1828
 
1826
1829
  return url, headers, payload
@@ -52,7 +52,7 @@ class BaseAPI:
52
52
  self.v1_models: str = urlunparse(parsed_url[:2] + (before_v1 + "models",) + ("",) * 3)
53
53
 
54
54
  if "v1/responses" in parsed_url.path:
55
- self.chat_url: str = urlunparse(parsed_url[:2] + ("v1/responses",) + ("",) * 3)
55
+ self.chat_url: str = api_url
56
56
  else:
57
57
  self.chat_url: str = urlunparse(parsed_url[:2] + (before_v1 + "chat/completions",) + ("",) * 3)
58
58
  self.image_url: str = urlunparse(parsed_url[:2] + (before_v1 + "images/generations",) + ("",) * 3)
@@ -89,6 +89,13 @@ class RepetitiveResponseError(Exception):
89
89
  self.count = count
90
90
 
91
91
 
92
+ class AllToolsMissingParametersError(Exception):
93
+ """Custom exception for when all tools are missing required parameters."""
94
+ def __init__(self, message, response_text):
95
+ super().__init__(message)
96
+ self.response_text = response_text
97
+
98
+
92
99
  class chatgpt(BaseLLM):
93
100
  """
94
101
  Official ChatGPT API
@@ -500,6 +507,9 @@ class chatgpt(BaseLLM):
500
507
  missing_required_params.append(f"Error: {tool_name} missing required parameters: {missing_required_params}")
501
508
  function_parameter = valid_function_parameters
502
509
 
510
+ if not function_parameter and missing_required_params:
511
+ raise AllToolsMissingParametersError("\n\n".join(missing_required_params), response_text=full_response)
512
+
503
513
  # 删除 task_complete 跟其他工具一起调用的情况,因为 task_complete 必须单独调用
504
514
  if len(function_parameter) > 1:
505
515
  function_parameter = [tool_dict for tool_dict in function_parameter if tool_dict.get("function_name", "") != "task_complete"]
@@ -810,6 +820,13 @@ class chatgpt(BaseLLM):
810
820
  {"role": "user", "content": "你的消息没有以[done]结尾,请重新输出"}
811
821
  ]
812
822
  continue
823
+ except AllToolsMissingParametersError as e:
824
+ self.logger.warning(f"All tools are missing required parameters: {e}. Retrying with corrective prompt.")
825
+ need_done_prompt = [
826
+ {"role": "assistant", "content": e.response_text},
827
+ {"role": "user", "content": f"{e.message},请重新输出"}
828
+ ]
829
+ continue
813
830
  except EmptyResponseError as e:
814
831
  self.logger.warning(f"{e}, retrying...")
815
832
  continue
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beswarm
3
- Version: 0.3.13
3
+ Version: 0.3.14
4
4
  Summary: MAS
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -10,16 +10,16 @@ beswarm/agents/chatgroup.py,sha256=PzrmRcDKAbB7cxL16nMod_CzPosDV6bfTmXxQVuv-AQ,1
10
10
  beswarm/agents/planact.py,sha256=dhPkMUaZLc1dO0TrI1Orr_i60iLzJHQIYBI_QjjSJwI,18723
11
11
  beswarm/aient/aient/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
12
12
  beswarm/aient/aient/architext/architext/__init__.py,sha256=79Ih1151rfcqZdr7F8HSZSTs_iT2SKd1xCkehMsXeXs,19
13
- beswarm/aient/aient/architext/architext/core.py,sha256=3io21wNZ-Za8VpQZn9nnc8qIjfON9fxMxURMC7fYCPY,37559
13
+ beswarm/aient/aient/architext/architext/core.py,sha256=E5QTM0NNoHPxRawH_Lmb01azAAlmLlm0bPy5c78zG38,37972
14
14
  beswarm/aient/aient/architext/test/openai_client.py,sha256=Dqtbmubv6vwF8uBqcayG0kbsiO65of7sgU2-DRBi-UM,4590
15
- beswarm/aient/aient/architext/test/test.py,sha256=kWsvKq8lYLuRVlU6Sqe7PyQAP15ENpemy5EV6Se4UpE,89019
15
+ beswarm/aient/aient/architext/test/test.py,sha256=c6wHwo8DQL5yeEQ3T1lqMleHJ9M5Sifnk4Qqk64Vv7w,90970
16
16
  beswarm/aient/aient/architext/test/test_save_load.py,sha256=o8DqH6gDYZkFkQy-a7blqLtJTRj5e4a-Lil48pJ0V3g,3260
17
17
  beswarm/aient/aient/core/__init__.py,sha256=NxjebTlku35S4Dzr16rdSqSTWUvvwEeACe8KvHJnjPg,34
18
18
  beswarm/aient/aient/core/log_config.py,sha256=kz2_yJv1p-o3lUQOwA3qh-LSc3wMHv13iCQclw44W9c,274
19
19
  beswarm/aient/aient/core/models.py,sha256=KMlCRLjtq1wQHZTJGqnbWhPS2cHq6eLdnk7peKDrzR8,7490
20
- beswarm/aient/aient/core/request.py,sha256=u9wkesp0JMQoJdLoDCNQQgiAB7a_W4Hs38uX6Ppqpi8,77836
20
+ beswarm/aient/aient/core/request.py,sha256=s9cRpSLmuujuPxqKfmT8X1_eRby4z3NREjlSEG5Bwzg,78052
21
21
  beswarm/aient/aient/core/response.py,sha256=VYpXfF6RO3Y-fTZMGV2p-bcrd73BPAKlz33gQkOcqjE,38462
22
- beswarm/aient/aient/core/utils.py,sha256=9T6Ze9sMnsX4NBWeYCgY3AlZdhh6HFV1LI5SojzZars,31751
22
+ beswarm/aient/aient/core/utils.py,sha256=jlEjtsCnnUxp-z9NLCiDbLBxEd9AE0zEWxnpjq7_5ao,31700
23
23
  beswarm/aient/aient/core/test/test_base_api.py,sha256=pWnycRJbuPSXKKU9AQjWrMAX1wiLC_014Qc9hh5C2Pw,524
24
24
  beswarm/aient/aient/core/test/test_geminimask.py,sha256=HFX8jDbNg_FjjgPNxfYaR-0-roUrOO-ND-FVsuxSoiw,13254
25
25
  beswarm/aient/aient/core/test/test_image.py,sha256=_T4peNGdXKBHHxyQNx12u-NTyFE8TlYI6NvvagsG2LE,319
@@ -27,7 +27,7 @@ beswarm/aient/aient/core/test/test_payload.py,sha256=8jBiJY1uidm1jzL-EiK0s6UGmW9
27
27
  beswarm/aient/aient/models/__init__.py,sha256=ZTiZgbfBPTjIPSKURE7t6hlFBVLRS9lluGbmqc1WjxQ,43
28
28
  beswarm/aient/aient/models/audio.py,sha256=FNW4lxG1IhxOU7L8mvcbaeC1nXk_lpUZQlg9ijQ0h_Q,1937
29
29
  beswarm/aient/aient/models/base.py,sha256=HWIGfa2A7OTccvHK0wG1-UlHB-yaWRC7hbi4oR1Mu1Y,7228
30
- beswarm/aient/aient/models/chatgpt.py,sha256=ZM0Ol_0vTZ5-5NjTolVfQzN47OyH1e8eJEDf2QRqwHA,43875
30
+ beswarm/aient/aient/models/chatgpt.py,sha256=lhn2Q2iSIB_edXgEv8bP7t4JZK1e3pZiImXjSMJR54Y,44736
31
31
  beswarm/aient/aient/plugins/__init__.py,sha256=p3KO6Aa3Lupos4i2SjzLQw1hzQTigOAfEHngsldrsyk,986
32
32
  beswarm/aient/aient/plugins/arXiv.py,sha256=yHjb6PS3GUWazpOYRMKMzghKJlxnZ5TX8z9F6UtUVow,1461
33
33
  beswarm/aient/aient/plugins/config.py,sha256=TGgZ5SnNKZ8MmdznrZ-TEq7s2ulhAAwTSKH89bci3dA,7079
@@ -121,8 +121,8 @@ beswarm/tools/subtasks.py,sha256=Fsf_542CkECcwFwxD-F38_IUsmk06xe1P7e6pBPTy4Y,128
121
121
  beswarm/tools/worker.py,sha256=mQ1qdrQ8MgL99byAbTvxfEByFFGN9mty3UHqHjARMQ8,2331
122
122
  beswarm/tools/write_csv.py,sha256=u0Hq18Ksfheb52MVtyLNCnSDHibITpsYBPs2ub7USYA,1466
123
123
  beswarm/tools/write_file.py,sha256=L2coBqz-aRFxPBvJBrbWbUJhu7p3oKAAGb9R144bFtk,4926
124
- beswarm-0.3.13.dist-info/METADATA,sha256=MQHN-a_l_axNIuLC3PR6h0r_3xWYTkMiy4dBC-K3frs,3878
125
- beswarm-0.3.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
126
- beswarm-0.3.13.dist-info/entry_points.txt,sha256=URK7Y4PDzBgxIecQnxsWTu4O-eaFa1CoAcNTWh5R7LM,45
127
- beswarm-0.3.13.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
128
- beswarm-0.3.13.dist-info/RECORD,,
124
+ beswarm-0.3.14.dist-info/METADATA,sha256=7EF549W5qhomzsWEHBSdg4ZJwQttF1VC72muLl2F9Jo,3878
125
+ beswarm-0.3.14.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
126
+ beswarm-0.3.14.dist-info/entry_points.txt,sha256=URK7Y4PDzBgxIecQnxsWTu4O-eaFa1CoAcNTWh5R7LM,45
127
+ beswarm-0.3.14.dist-info/top_level.txt,sha256=pJw4O87wvt5882smuSO6DfByJz7FJ8SxxT8h9fHCmpo,8
128
+ beswarm-0.3.14.dist-info/RECORD,,