aient 1.0.44__tar.gz → 1.0.46__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 (72) hide show
  1. {aient-1.0.44/src/aient.egg-info → aient-1.0.46}/PKG-INFO +1 -1
  2. {aient-1.0.44 → aient-1.0.46}/setup.py +1 -1
  3. {aient-1.0.44 → aient-1.0.46}/src/aient/core/models.py +4 -0
  4. {aient-1.0.44 → aient-1.0.46}/src/aient/core/request.py +26 -10
  5. {aient-1.0.44 → aient-1.0.46}/src/aient/core/response.py +0 -2
  6. {aient-1.0.44 → aient-1.0.46}/src/aient/core/utils.py +32 -4
  7. {aient-1.0.44 → aient-1.0.46}/src/aient/models/chatgpt.py +6 -1
  8. {aient-1.0.44 → aient-1.0.46/src/aient.egg-info}/PKG-INFO +1 -1
  9. {aient-1.0.44 → aient-1.0.46}/LICENSE +0 -0
  10. {aient-1.0.44 → aient-1.0.46}/MANIFEST.in +0 -0
  11. {aient-1.0.44 → aient-1.0.46}/README.md +0 -0
  12. {aient-1.0.44 → aient-1.0.46}/setup.cfg +0 -0
  13. {aient-1.0.44 → aient-1.0.46}/src/aient/__init__.py +0 -0
  14. {aient-1.0.44 → aient-1.0.46}/src/aient/core/.git +0 -0
  15. {aient-1.0.44 → aient-1.0.46}/src/aient/core/__init__.py +0 -0
  16. {aient-1.0.44 → aient-1.0.46}/src/aient/core/log_config.py +0 -0
  17. {aient-1.0.44 → aient-1.0.46}/src/aient/core/test/test_base_api.py +0 -0
  18. {aient-1.0.44 → aient-1.0.46}/src/aient/core/test/test_image.py +0 -0
  19. {aient-1.0.44 → aient-1.0.46}/src/aient/core/test/test_payload.py +0 -0
  20. {aient-1.0.44 → aient-1.0.46}/src/aient/models/__init__.py +0 -0
  21. {aient-1.0.44 → aient-1.0.46}/src/aient/models/audio.py +0 -0
  22. {aient-1.0.44 → aient-1.0.46}/src/aient/models/base.py +0 -0
  23. {aient-1.0.44 → aient-1.0.46}/src/aient/models/claude.py +0 -0
  24. {aient-1.0.44 → aient-1.0.46}/src/aient/models/duckduckgo.py +0 -0
  25. {aient-1.0.44 → aient-1.0.46}/src/aient/models/gemini.py +0 -0
  26. {aient-1.0.44 → aient-1.0.46}/src/aient/models/groq.py +0 -0
  27. {aient-1.0.44 → aient-1.0.46}/src/aient/models/vertex.py +0 -0
  28. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/__init__.py +0 -0
  29. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/arXiv.py +0 -0
  30. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/config.py +0 -0
  31. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/image.py +0 -0
  32. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/registry.py +0 -0
  33. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/run_python.py +0 -0
  34. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/today.py +0 -0
  35. {aient-1.0.44 → aient-1.0.46}/src/aient/plugins/websearch.py +0 -0
  36. {aient-1.0.44 → aient-1.0.46}/src/aient/utils/__init__.py +0 -0
  37. {aient-1.0.44 → aient-1.0.46}/src/aient/utils/prompt.py +0 -0
  38. {aient-1.0.44 → aient-1.0.46}/src/aient/utils/scripts.py +0 -0
  39. {aient-1.0.44 → aient-1.0.46}/src/aient.egg-info/SOURCES.txt +0 -0
  40. {aient-1.0.44 → aient-1.0.46}/src/aient.egg-info/dependency_links.txt +0 -0
  41. {aient-1.0.44 → aient-1.0.46}/src/aient.egg-info/requires.txt +0 -0
  42. {aient-1.0.44 → aient-1.0.46}/src/aient.egg-info/top_level.txt +0 -0
  43. {aient-1.0.44 → aient-1.0.46}/test/test.py +0 -0
  44. {aient-1.0.44 → aient-1.0.46}/test/test_API.py +0 -0
  45. {aient-1.0.44 → aient-1.0.46}/test/test_Deepbricks.py +0 -0
  46. {aient-1.0.44 → aient-1.0.46}/test/test_Web_crawler.py +0 -0
  47. {aient-1.0.44 → aient-1.0.46}/test/test_aiwaves.py +0 -0
  48. {aient-1.0.44 → aient-1.0.46}/test/test_aiwaves_arxiv.py +0 -0
  49. {aient-1.0.44 → aient-1.0.46}/test/test_ask_gemini.py +0 -0
  50. {aient-1.0.44 → aient-1.0.46}/test/test_class.py +0 -0
  51. {aient-1.0.44 → aient-1.0.46}/test/test_claude.py +0 -0
  52. {aient-1.0.44 → aient-1.0.46}/test/test_claude_zh_char.py +0 -0
  53. {aient-1.0.44 → aient-1.0.46}/test/test_ddg_search.py +0 -0
  54. {aient-1.0.44 → aient-1.0.46}/test/test_download_pdf.py +0 -0
  55. {aient-1.0.44 → aient-1.0.46}/test/test_gemini.py +0 -0
  56. {aient-1.0.44 → aient-1.0.46}/test/test_get_token_dict.py +0 -0
  57. {aient-1.0.44 → aient-1.0.46}/test/test_google_search.py +0 -0
  58. {aient-1.0.44 → aient-1.0.46}/test/test_jieba.py +0 -0
  59. {aient-1.0.44 → aient-1.0.46}/test/test_json.py +0 -0
  60. {aient-1.0.44 → aient-1.0.46}/test/test_langchain_search_old.py +0 -0
  61. {aient-1.0.44 → aient-1.0.46}/test/test_logging.py +0 -0
  62. {aient-1.0.44 → aient-1.0.46}/test/test_ollama.py +0 -0
  63. {aient-1.0.44 → aient-1.0.46}/test/test_plugin.py +0 -0
  64. {aient-1.0.44 → aient-1.0.46}/test/test_py_run.py +0 -0
  65. {aient-1.0.44 → aient-1.0.46}/test/test_requests.py +0 -0
  66. {aient-1.0.44 → aient-1.0.46}/test/test_search.py +0 -0
  67. {aient-1.0.44 → aient-1.0.46}/test/test_tikitoken.py +0 -0
  68. {aient-1.0.44 → aient-1.0.46}/test/test_token.py +0 -0
  69. {aient-1.0.44 → aient-1.0.46}/test/test_url.py +0 -0
  70. {aient-1.0.44 → aient-1.0.46}/test/test_whisper.py +0 -0
  71. {aient-1.0.44 → aient-1.0.46}/test/test_wildcard.py +0 -0
  72. {aient-1.0.44 → aient-1.0.46}/test/test_yjh.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aient
3
- Version: 1.0.44
3
+ Version: 1.0.46
4
4
  Summary: Aient: The Awakening of Agent.
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
 
5
5
  setup(
6
6
  name="aient",
7
- version="1.0.44",
7
+ version="1.0.46",
8
8
  description="Aient: The Awakening of Agent.",
9
9
  long_description=Path.open(Path("README.md"), encoding="utf-8").read(),
10
10
  long_description_content_type="text/markdown",
@@ -86,6 +86,9 @@ class Thinking(BaseModel):
86
86
  budget_tokens: Optional[int] = None
87
87
  type: Optional[Literal["enabled", "disabled"]] = None
88
88
 
89
+ class StreamOptions(BaseModel):
90
+ include_usage: Optional[bool] = None
91
+
89
92
  class RequestModel(BaseRequest):
90
93
  model: str
91
94
  messages: List[Message]
@@ -105,6 +108,7 @@ class RequestModel(BaseRequest):
105
108
  tools: Optional[List[Tool]] = None
106
109
  response_format: Optional[ResponseFormat] = None
107
110
  thinking: Optional[Thinking] = None
111
+ stream_options: Optional[StreamOptions] = None
108
112
 
109
113
  def get_last_text_message(self) -> Optional[str]:
110
114
  for message in reversed(self.messages):
@@ -96,7 +96,8 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
96
96
  content[0]["text"] = re.sub(r"_+", "_", content[0]["text"])
97
97
  systemInstruction = {"parts": content}
98
98
 
99
- if "gemini-2.0-flash-exp" in original_model or "gemini-1.5" in original_model:
99
+ off_models = ["gemini-2.0-flash-exp", "gemini-1.5", "gemini-2.5-pro"]
100
+ if any(off_model in original_model for off_model in off_models):
100
101
  safety_settings = "OFF"
101
102
  else:
102
103
  safety_settings = "BLOCK_NONE"
@@ -119,7 +120,11 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
119
120
  {
120
121
  "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
121
122
  "threshold": safety_settings
122
- }
123
+ },
124
+ {
125
+ "category": "HARM_CATEGORY_CIVIC_INTEGRITY",
126
+ "threshold": "BLOCK_NONE"
127
+ },
123
128
  ]
124
129
  }
125
130
 
@@ -144,7 +149,8 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
144
149
  'include_usage',
145
150
  'logprobs',
146
151
  'top_logprobs',
147
- 'response_format'
152
+ 'response_format',
153
+ 'stream_options',
148
154
  ]
149
155
  generation_config = {}
150
156
 
@@ -190,9 +196,12 @@ async def get_gemini_payload(request, engine, provider, api_key=None):
190
196
  else:
191
197
  payload[field] = value
192
198
 
193
- if generation_config:
194
- payload["generationConfig"] = generation_config
195
- if "maxOutputTokens" not in generation_config:
199
+ max_token_65k_models = ["gemini-2.5-pro", "gemini-2.0-pro", "gemini-2.0-flash-thinking"]
200
+ payload["generationConfig"] = generation_config
201
+ if "maxOutputTokens" not in generation_config:
202
+ if any(pro_model in original_model for pro_model in max_token_65k_models):
203
+ payload["generationConfig"]["maxOutputTokens"] = 65536
204
+ else:
196
205
  payload["generationConfig"]["maxOutputTokens"] = 8192
197
206
 
198
207
  if request.model.endswith("-search"):
@@ -277,7 +286,8 @@ async def get_vertex_gemini_payload(request, engine, provider, api_key=None):
277
286
  original_model = model_dict[request.model]
278
287
  search_tool = None
279
288
 
280
- if "gemini-2.0" in original_model or "gemini-exp" in original_model:
289
+ pro_models = ["gemini-2.5-pro", "gemini-2.0-pro", "gemini-exp"]
290
+ if any(pro_model in original_model for pro_model in pro_models):
281
291
  location = gemini2
282
292
  search_tool = {"googleSearch": {}}
283
293
  else:
@@ -384,7 +394,8 @@ async def get_vertex_gemini_payload(request, engine, provider, api_key=None):
384
394
  'user',
385
395
  'include_usage',
386
396
  'logprobs',
387
- 'top_logprobs'
397
+ 'top_logprobs',
398
+ 'stream_options',
388
399
  ]
389
400
  generation_config = {}
390
401
 
@@ -549,6 +560,7 @@ async def get_vertex_claude_payload(request, engine, provider, api_key=None):
549
560
  'n',
550
561
  'user',
551
562
  'include_usage',
563
+ 'stream_options',
552
564
  ]
553
565
 
554
566
  for field, value in request.model_dump(exclude_unset=True).items():
@@ -845,6 +857,7 @@ async def get_openrouter_payload(request, engine, provider, api_key=None):
845
857
  'n',
846
858
  'user',
847
859
  'include_usage',
860
+ 'stream_options',
848
861
  ]
849
862
 
850
863
  for field, value in request.model_dump(exclude_unset=True).items():
@@ -912,7 +925,8 @@ async def get_cohere_payload(request, engine, provider, api_key=None):
912
925
  'user',
913
926
  'include_usage',
914
927
  'logprobs',
915
- 'top_logprobs'
928
+ 'top_logprobs',
929
+ 'stream_options',
916
930
  ]
917
931
 
918
932
  for field, value in request.model_dump(exclude_unset=True).items():
@@ -959,7 +973,8 @@ async def get_cloudflare_payload(request, engine, provider, api_key=None):
959
973
  'user',
960
974
  'include_usage',
961
975
  'logprobs',
962
- 'top_logprobs'
976
+ 'top_logprobs',
977
+ 'stream_options',
963
978
  ]
964
979
 
965
980
  for field, value in request.model_dump(exclude_unset=True).items():
@@ -1141,6 +1156,7 @@ async def get_claude_payload(request, engine, provider, api_key=None):
1141
1156
  'n',
1142
1157
  'user',
1143
1158
  'include_usage',
1159
+ 'stream_options',
1144
1160
  ]
1145
1161
 
1146
1162
  for field, value in request.model_dump(exclude_unset=True).items():
@@ -50,7 +50,6 @@ async def fetch_gemini_response_stream(client, url, headers, payload, model):
50
50
  try:
51
51
  json_data = json.loads( "{" + line + "}")
52
52
  content = json_data.get('text', '')
53
- content = "\n".join(content.split("\\n"))
54
53
  # content = content.replace("\n", "\n\n")
55
54
  # if last_text_line == 0 and is_thinking:
56
55
  # content = "> " + content.lstrip()
@@ -108,7 +107,6 @@ async def fetch_vertex_claude_response_stream(client, url, headers, payload, mod
108
107
  try:
109
108
  json_data = json.loads( "{" + line + "}")
110
109
  content = json_data.get('text', '')
111
- content = "\n".join(content.split("\\n"))
112
110
  sse_string = await generate_sse_response(timestamp, model, content=content)
113
111
  yield sse_string
114
112
  except json.JSONDecodeError:
@@ -155,7 +155,8 @@ def update_initial_model(provider):
155
155
  proxy = safe_get(provider, "preferences", "proxy", default=None)
156
156
  client_config = get_proxy(proxy)
157
157
  if engine == "gemini":
158
- url = "https://generativelanguage.googleapis.com/v1beta/models"
158
+ before_v1 = api_url.split("/v1beta")[0]
159
+ url = before_v1 + "/v1beta/models"
159
160
  params = {"key": api}
160
161
  with httpx.Client(**client_config) as client:
161
162
  response = client.get(url, params=params)
@@ -288,7 +289,7 @@ class ThreadSafeCircularList:
288
289
  # self.requests[item] = []
289
290
  logger.warning(f"API key {item} 已进入冷却状态,冷却时间 {cooling_time} 秒")
290
291
 
291
- async def is_rate_limited(self, item, model: str = None) -> bool:
292
+ async def is_rate_limited(self, item, model: str = None, is_check: bool = False) -> bool:
292
293
  now = time()
293
294
  # 检查是否在冷却中
294
295
  if now < self.cooling_until[item]:
@@ -321,7 +322,8 @@ class ThreadSafeCircularList:
321
322
  # 使用特定模型的请求记录进行计算
322
323
  recent_requests = sum(1 for req in self.requests[item][model_key] if req > now - limit_period)
323
324
  if recent_requests >= limit_count:
324
- logger.warning(f"API key {item} 对模型 {model_key} 已达到速率限制 ({limit_count}/{limit_period}秒)")
325
+ if not is_check:
326
+ logger.warning(f"API key {item}: model: {model_key} has been rate limited ({limit_count}/{limit_period} seconds)")
325
327
  return True
326
328
 
327
329
  # 清理太旧的请求记录
@@ -329,7 +331,9 @@ class ThreadSafeCircularList:
329
331
  self.requests[item][model_key] = [req for req in self.requests[item][model_key] if req > now - max_period]
330
332
 
331
333
  # 记录新的请求
332
- self.requests[item][model_key].append(now)
334
+ if not is_check:
335
+ self.requests[item][model_key].append(now)
336
+
333
337
  return False
334
338
 
335
339
  async def next(self, model: str = None):
@@ -349,6 +353,30 @@ class ThreadSafeCircularList:
349
353
  logger.warning(f"All API keys are rate limited!")
350
354
  raise HTTPException(status_code=429, detail="Too many requests")
351
355
 
356
+ async def is_all_rate_limited(self, model: str = None) -> bool:
357
+ """检查是否所有的items都被速率限制
358
+
359
+ 与next方法不同,此方法不会改变任何内部状态(如self.index),
360
+ 仅返回一个布尔值表示是否所有的key都被限制。
361
+
362
+ Args:
363
+ model: 要检查的模型名称,默认为None
364
+
365
+ Returns:
366
+ bool: 如果所有items都被速率限制返回True,否则返回False
367
+ """
368
+ if len(self.items) == 0:
369
+ return False
370
+
371
+ async with self.lock:
372
+ for item in self.items:
373
+ if not await self.is_rate_limited(item, model, is_check=True):
374
+ return False
375
+
376
+ # 如果遍历完所有items都被限制,返回True
377
+ # logger.debug(f"Check result: all items are rate limited!")
378
+ return True
379
+
352
380
  async def after_next_current(self):
353
381
  # 返回当前取出的 API,因为已经调用了 next,所以当前API应该是上一个
354
382
  if len(self.items) == 0:
@@ -159,7 +159,9 @@ class chatgpt(BaseLLM):
159
159
 
160
160
  conversation_len = len(self.conversation[convo_id]) - 1
161
161
  message_index = 0
162
- # print(json.dumps(self.conversation[convo_id], indent=4, ensure_ascii=False))
162
+ # if self.print_log:
163
+ # replaced_text = json.loads(re.sub(r';base64,([A-Za-z0-9+/=]+)', ';base64,***', json.dumps(self.conversation[convo_id])))
164
+ # print(json.dumps(replaced_text, indent=4, ensure_ascii=False))
163
165
  while message_index < conversation_len:
164
166
  if self.conversation[convo_id][message_index]["role"] == self.conversation[convo_id][message_index + 1]["role"]:
165
167
  if self.conversation[convo_id][message_index].get("content") and self.conversation[convo_id][message_index + 1].get("content"):
@@ -180,6 +182,9 @@ class chatgpt(BaseLLM):
180
182
  and type(self.conversation[convo_id][message_index + 1]["content"]) == dict:
181
183
  self.conversation[convo_id][message_index]["content"] = [self.conversation[convo_id][message_index]["content"]]
182
184
  self.conversation[convo_id][message_index + 1]["content"] = [self.conversation[convo_id][message_index + 1]["content"]]
185
+ if type(self.conversation[convo_id][message_index]["content"]) == list \
186
+ and type(self.conversation[convo_id][message_index + 1]["content"]) == dict:
187
+ self.conversation[convo_id][message_index + 1]["content"] = [self.conversation[convo_id][message_index + 1]["content"]]
183
188
  self.conversation[convo_id][message_index]["content"] += self.conversation[convo_id][message_index + 1]["content"]
184
189
  self.conversation[convo_id].pop(message_index + 1)
185
190
  conversation_len = conversation_len - 1
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aient
3
- Version: 1.0.44
3
+ Version: 1.0.46
4
4
  Summary: Aient: The Awakening of Agent.
5
5
  Description-Content-Type: text/markdown
6
6
  License-File: LICENSE
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
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
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
File without changes
File without changes
File without changes
File without changes
File without changes