aient 1.2.46__py3-none-any.whl → 1.2.48__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
  # ==============================================================================
aient/core/request.py CHANGED
@@ -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
@@ -1152,7 +1152,7 @@ async def get_gpt_payload(request, engine, provider, api_key=None):
1152
1152
  if key == request.model:
1153
1153
  for k, v in value.items():
1154
1154
  payload[k] = v
1155
- 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:
1156
1156
  payload[key] = value
1157
1157
 
1158
1158
  return url, headers, payload
@@ -1250,7 +1250,7 @@ async def get_azure_payload(request, engine, provider, api_key=None):
1250
1250
  if key == request.model:
1251
1251
  for k, v in value.items():
1252
1252
  payload[k] = v
1253
- 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:
1254
1254
  payload[key] = value
1255
1255
 
1256
1256
  return url, headers, payload
@@ -1370,7 +1370,7 @@ async def get_azure_databricks_payload(request, engine, provider, api_key=None):
1370
1370
  if key == request.model:
1371
1371
  for k, v in value.items():
1372
1372
  payload[k] = v
1373
- 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:
1374
1374
  payload[key] = value
1375
1375
 
1376
1376
  return url, headers, payload
@@ -1457,7 +1457,7 @@ async def get_openrouter_payload(request, engine, provider, api_key=None):
1457
1457
  if key == request.model:
1458
1458
  for k, v in value.items():
1459
1459
  payload[k] = v
1460
- 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:
1461
1461
  payload[key] = value
1462
1462
 
1463
1463
  return url, headers, payload
@@ -1823,7 +1823,7 @@ async def get_claude_payload(request, engine, provider, api_key=None):
1823
1823
  if key == request.model:
1824
1824
  for k, v in value.items():
1825
1825
  payload[k] = v
1826
- 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:
1827
1827
  payload[key] = value
1828
1828
 
1829
1829
  return url, headers, payload
aient/models/chatgpt.py CHANGED
@@ -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: aient
3
- Version: 1.2.46
3
+ Version: 1.2.48
4
4
  Summary: Aient: The Awakening of Agent.
5
5
  Requires-Python: >=3.11
6
6
  Description-Content-Type: text/markdown
@@ -1,13 +1,13 @@
1
1
  aient/__init__.py,sha256=SRfF7oDVlOOAi6nGKiJIUK6B_arqYLO9iSMp-2IZZps,21
2
2
  aient/architext/architext/__init__.py,sha256=79Ih1151rfcqZdr7F8HSZSTs_iT2SKd1xCkehMsXeXs,19
3
- aient/architext/architext/core.py,sha256=3io21wNZ-Za8VpQZn9nnc8qIjfON9fxMxURMC7fYCPY,37559
3
+ aient/architext/architext/core.py,sha256=E5QTM0NNoHPxRawH_Lmb01azAAlmLlm0bPy5c78zG38,37972
4
4
  aient/architext/test/openai_client.py,sha256=Dqtbmubv6vwF8uBqcayG0kbsiO65of7sgU2-DRBi-UM,4590
5
- aient/architext/test/test.py,sha256=kWsvKq8lYLuRVlU6Sqe7PyQAP15ENpemy5EV6Se4UpE,89019
5
+ aient/architext/test/test.py,sha256=c6wHwo8DQL5yeEQ3T1lqMleHJ9M5Sifnk4Qqk64Vv7w,90970
6
6
  aient/architext/test/test_save_load.py,sha256=o8DqH6gDYZkFkQy-a7blqLtJTRj5e4a-Lil48pJ0V3g,3260
7
7
  aient/core/__init__.py,sha256=NxjebTlku35S4Dzr16rdSqSTWUvvwEeACe8KvHJnjPg,34
8
8
  aient/core/log_config.py,sha256=kz2_yJv1p-o3lUQOwA3qh-LSc3wMHv13iCQclw44W9c,274
9
9
  aient/core/models.py,sha256=KMlCRLjtq1wQHZTJGqnbWhPS2cHq6eLdnk7peKDrzR8,7490
10
- aient/core/request.py,sha256=JwTlgdFJjf2mi9UbGDAgI2dRj49NnWXnnww7S6VsPIM,77919
10
+ aient/core/request.py,sha256=s9cRpSLmuujuPxqKfmT8X1_eRby4z3NREjlSEG5Bwzg,78052
11
11
  aient/core/response.py,sha256=VYpXfF6RO3Y-fTZMGV2p-bcrd73BPAKlz33gQkOcqjE,38462
12
12
  aient/core/utils.py,sha256=jlEjtsCnnUxp-z9NLCiDbLBxEd9AE0zEWxnpjq7_5ao,31700
13
13
  aient/core/test/test_base_api.py,sha256=pWnycRJbuPSXKKU9AQjWrMAX1wiLC_014Qc9hh5C2Pw,524
@@ -17,7 +17,7 @@ aient/core/test/test_payload.py,sha256=8jBiJY1uidm1jzL-EiK0s6UGmW9XkdsuuKFGrwFhF
17
17
  aient/models/__init__.py,sha256=ZTiZgbfBPTjIPSKURE7t6hlFBVLRS9lluGbmqc1WjxQ,43
18
18
  aient/models/audio.py,sha256=FNW4lxG1IhxOU7L8mvcbaeC1nXk_lpUZQlg9ijQ0h_Q,1937
19
19
  aient/models/base.py,sha256=HWIGfa2A7OTccvHK0wG1-UlHB-yaWRC7hbi4oR1Mu1Y,7228
20
- aient/models/chatgpt.py,sha256=ZM0Ol_0vTZ5-5NjTolVfQzN47OyH1e8eJEDf2QRqwHA,43875
20
+ aient/models/chatgpt.py,sha256=lhn2Q2iSIB_edXgEv8bP7t4JZK1e3pZiImXjSMJR54Y,44736
21
21
  aient/plugins/__init__.py,sha256=p3KO6Aa3Lupos4i2SjzLQw1hzQTigOAfEHngsldrsyk,986
22
22
  aient/plugins/arXiv.py,sha256=yHjb6PS3GUWazpOYRMKMzghKJlxnZ5TX8z9F6UtUVow,1461
23
23
  aient/plugins/config.py,sha256=TGgZ5SnNKZ8MmdznrZ-TEq7s2ulhAAwTSKH89bci3dA,7079
@@ -33,8 +33,8 @@ aient/plugins/websearch.py,sha256=aPsBjUQ3zQ4gzNrbVq7BMh28ENj9h_fSAeJFF2h9TNk,15
33
33
  aient/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  aient/utils/prompt.py,sha256=ZvGAt_ImJ_CGbDnWgpsWskfSV5fCkpFKRpNQjYL7M7s,11100
35
35
  aient/utils/scripts.py,sha256=D_-BCLHV_PS9r6SLXsdEAyey4bVWte-jMMJJKSx0Pcg,42530
36
- aient-1.2.46.dist-info/licenses/LICENSE,sha256=XNdbcWldt0yaNXXWB_Bakoqnxb3OVhUft4MgMA_71ds,1051
37
- aient-1.2.46.dist-info/METADATA,sha256=X6zo3KmNSARw8KxmX6syoPTmQq2Fw2BWM3vfO8nSjDA,4842
38
- aient-1.2.46.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
- aient-1.2.46.dist-info/top_level.txt,sha256=3oXzrP5sAVvyyqabpeq8A2_vfMtY554r4bVE-OHBrZk,6
40
- aient-1.2.46.dist-info/RECORD,,
36
+ aient-1.2.48.dist-info/licenses/LICENSE,sha256=XNdbcWldt0yaNXXWB_Bakoqnxb3OVhUft4MgMA_71ds,1051
37
+ aient-1.2.48.dist-info/METADATA,sha256=Xs-1PxyvFUMT-0KlAnD9Ntxxr8IyaBYAap603U0nf9M,4842
38
+ aient-1.2.48.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
39
+ aient-1.2.48.dist-info/top_level.txt,sha256=3oXzrP5sAVvyyqabpeq8A2_vfMtY554r4bVE-OHBrZk,6
40
+ aient-1.2.48.dist-info/RECORD,,
File without changes