aient 1.0.37__py3-none-any.whl → 1.0.39__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.
- aient/core/request.py +5 -0
- aient/models/chatgpt.py +28 -15
- aient/utils/scripts.py +316 -0
- {aient-1.0.37.dist-info → aient-1.0.39.dist-info}/METADATA +1 -1
- {aient-1.0.37.dist-info → aient-1.0.39.dist-info}/RECORD +8 -8
- {aient-1.0.37.dist-info → aient-1.0.39.dist-info}/WHEEL +0 -0
- {aient-1.0.37.dist-info → aient-1.0.39.dist-info}/licenses/LICENSE +0 -0
- {aient-1.0.37.dist-info → aient-1.0.39.dist-info}/top_level.txt +0 -0
aient/core/request.py
CHANGED
@@ -675,6 +675,11 @@ async def get_gpt_payload(request, engine, provider, api_key=None):
|
|
675
675
|
if "temperature" in payload:
|
676
676
|
payload.pop("temperature")
|
677
677
|
|
678
|
+
# 代码生成/数学解题 0.0
|
679
|
+
# 数据抽取/分析 1.0
|
680
|
+
# 通用对话 1.3
|
681
|
+
# 翻译 1.3
|
682
|
+
# 创意类写作/诗歌创作 1.5
|
678
683
|
if "deepseek-r" in original_model.lower():
|
679
684
|
if "temperature" not in payload:
|
680
685
|
payload["temperature"] = 0.6
|
aient/models/chatgpt.py
CHANGED
@@ -12,7 +12,7 @@ from pathlib import Path
|
|
12
12
|
|
13
13
|
from .base import BaseLLM
|
14
14
|
from ..plugins import PLUGINS, get_tools_result_async, function_call_list, update_tools_config
|
15
|
-
from ..utils.scripts import check_json, safe_get, async_generator_to_sync
|
15
|
+
from ..utils.scripts import check_json, safe_get, async_generator_to_sync, parse_function_xml
|
16
16
|
from ..core.request import prepare_request_payload
|
17
17
|
from ..core.response import fetch_response_stream
|
18
18
|
|
@@ -131,20 +131,26 @@ class chatgpt(BaseLLM):
|
|
131
131
|
matching_message = next(filter(lambda x: safe_get(x, "tool_calls", 0, "function", "name", default="") == 'get_next_pdf', self.conversation[convo_id]), None)
|
132
132
|
if matching_message is not None:
|
133
133
|
self.conversation[convo_id] = self.conversation[convo_id][:self.conversation[convo_id].index(matching_message)]
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
"
|
142
|
-
"
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
134
|
+
|
135
|
+
if not (all(value == False for value in self.plugins.values()) or self.use_plugins == False):
|
136
|
+
self.conversation[convo_id].append({
|
137
|
+
"role": "assistant",
|
138
|
+
"tool_calls": [
|
139
|
+
{
|
140
|
+
"id": function_call_id,
|
141
|
+
"type": "function",
|
142
|
+
"function": {
|
143
|
+
"name": function_name,
|
144
|
+
"arguments": function_arguments,
|
145
|
+
},
|
146
|
+
}
|
147
|
+
],
|
148
|
+
})
|
149
|
+
self.conversation[convo_id].append({"role": role, "tool_call_id": function_call_id, "content": message})
|
150
|
+
else:
|
151
|
+
self.conversation[convo_id].append({"role": "assistant", "content": "I will use tool: " + function_name + ". tool arguments:" + function_arguments + ". I will get the tool call result in the next user response."})
|
152
|
+
self.conversation[convo_id].append({"role": "user", "content": f"[{function_name} Result]\n\n" + message})
|
153
|
+
|
148
154
|
else:
|
149
155
|
print('\033[31m')
|
150
156
|
print("error: add_to_conversation message is None or empty")
|
@@ -390,6 +396,13 @@ class chatgpt(BaseLLM):
|
|
390
396
|
if response_role is None:
|
391
397
|
response_role = "assistant"
|
392
398
|
|
399
|
+
function_parameter = parse_function_xml(full_response)
|
400
|
+
if function_parameter['function_name']:
|
401
|
+
need_function_call = True
|
402
|
+
function_call_name = function_parameter['function_name']
|
403
|
+
function_full_response = json.dumps(function_parameter['parameter'])
|
404
|
+
function_call_id = function_parameter['function_name'] + "_tool_call"
|
405
|
+
|
393
406
|
# 处理函数调用
|
394
407
|
if need_function_call:
|
395
408
|
if self.print_log:
|
aient/utils/scripts.py
CHANGED
@@ -231,5 +231,321 @@ def async_generator_to_sync(async_gen):
|
|
231
231
|
except Exception as e:
|
232
232
|
print(f"Error during cleanup: {e}")
|
233
233
|
|
234
|
+
def parse_tools_from_cursor_prompt(text):
|
235
|
+
import json
|
236
|
+
import re
|
237
|
+
|
238
|
+
# 从 cursor_prompt 中提取 <tools> 标签内的 JSON 字符串
|
239
|
+
tools_match = re.search(r"<tools>\n(.*?)\n</tools>", text, re.DOTALL)
|
240
|
+
if tools_match:
|
241
|
+
tools_json_string = tools_match.group(1).strip()
|
242
|
+
try:
|
243
|
+
tools_list_data = json.loads(tools_json_string, strict=False)
|
244
|
+
return tools_list_data
|
245
|
+
except json.JSONDecodeError as e:
|
246
|
+
print(f"解析 JSON 时出错: {e}")
|
247
|
+
return []
|
248
|
+
|
249
|
+
from dataclasses import dataclass
|
250
|
+
from typing import List, Callable, Optional, TypeVar, Generic, Union, Dict, Any
|
251
|
+
|
252
|
+
# 定义结果类型
|
253
|
+
@dataclass
|
254
|
+
class XmlMatcherResult:
|
255
|
+
matched: bool
|
256
|
+
data: str = ""
|
257
|
+
|
258
|
+
# 泛型类型变量,用于 transform 的返回类型
|
259
|
+
R = TypeVar('R')
|
260
|
+
|
261
|
+
class XmlMatcher(Generic[R]):
|
262
|
+
def __init__(self,
|
263
|
+
tag_name: str,
|
264
|
+
transform: Optional[Callable[[XmlMatcherResult], R]] = None,
|
265
|
+
position: int = 0):
|
266
|
+
self.tag_name: str = tag_name
|
267
|
+
self.transform: Optional[Callable[[XmlMatcherResult], R]] = transform
|
268
|
+
self.position: int = position
|
269
|
+
|
270
|
+
self.index: int = 0
|
271
|
+
self.chunks: List[XmlMatcherResult] = []
|
272
|
+
self.cached: List[str] = []
|
273
|
+
self.matched: bool = False
|
274
|
+
self.state: str = "TEXT" # "TEXT", "TAG_OPEN", "TAG_CLOSE"
|
275
|
+
self.depth: int = 0
|
276
|
+
self.pointer: int = 0
|
277
|
+
|
278
|
+
def _collect(self):
|
279
|
+
"""将缓存的字符收集到 chunks 中"""
|
280
|
+
if not self.cached:
|
281
|
+
return
|
282
|
+
|
283
|
+
data = "".join(self.cached)
|
284
|
+
# 检查是否需要合并到上一个 chunk
|
285
|
+
# 仅当当前缓存的匹配状态与上一个 chunk 相同时才合并
|
286
|
+
last = self.chunks[-1] if self.chunks else None
|
287
|
+
current_matched_state = self.matched if self.state == "TEXT" else (self.depth > 0) # 在标签解析过程中,匹配状态取决于深度
|
288
|
+
|
289
|
+
if last and last.matched == current_matched_state:
|
290
|
+
last.data += data
|
291
|
+
else:
|
292
|
+
# 只有当 data 不为空时才添加新的 chunk
|
293
|
+
if data:
|
294
|
+
self.chunks.append(XmlMatcherResult(data=data, matched=current_matched_state))
|
295
|
+
|
296
|
+
self.cached = []
|
297
|
+
|
298
|
+
def _pop(self) -> List[Union[XmlMatcherResult, R]]:
|
299
|
+
"""返回处理过的 chunks 并清空列表"""
|
300
|
+
chunks_to_return = self.chunks
|
301
|
+
self.chunks = []
|
302
|
+
if not self.transform:
|
303
|
+
# 如果没有 transform 函数,直接返回原始结果列表
|
304
|
+
# 需要显式类型转换,因为泛型 R 默认为 XmlMatcherResult
|
305
|
+
return [chunk for chunk in chunks_to_return] # type: ignore
|
306
|
+
# 应用 transform 函数
|
307
|
+
return [self.transform(chunk) for chunk in chunks_to_return]
|
308
|
+
|
309
|
+
def _update(self, chunk: str):
|
310
|
+
"""处理输入字符串块的核心逻辑"""
|
311
|
+
for char in chunk:
|
312
|
+
current_char_processed = False # 标记当前字符是否已被状态机逻辑处理
|
313
|
+
|
314
|
+
if self.state == "TEXT":
|
315
|
+
if char == "<" and (self.pointer >= self.position or self.matched):
|
316
|
+
self._collect()
|
317
|
+
self.state = "TAG_OPEN"
|
318
|
+
self.cached.append(char)
|
319
|
+
self.index = 0 # 重置 index 以开始匹配标签名或跳过空格
|
320
|
+
current_char_processed = True
|
321
|
+
# else: 保持在 TEXT 状态,字符将在循环末尾添加到 cached
|
322
|
+
|
323
|
+
elif self.state == "TAG_OPEN":
|
324
|
+
self.cached.append(char)
|
325
|
+
current_char_processed = True
|
326
|
+
|
327
|
+
tag_name_len = len(self.tag_name)
|
328
|
+
|
329
|
+
# 状态: 刚进入 < 之后
|
330
|
+
if self.index == 0:
|
331
|
+
if char == "/":
|
332
|
+
self.state = "TAG_CLOSE"
|
333
|
+
# index 保持 0,准备匹配闭合标签名或跳过空格
|
334
|
+
elif char.isspace():
|
335
|
+
# 跳过 < 后的空格
|
336
|
+
pass # index 保持 0
|
337
|
+
elif char == self.tag_name[0]:
|
338
|
+
# 开始匹配标签名
|
339
|
+
self.index = 1
|
340
|
+
else:
|
341
|
+
# 无效标签开头 (不是 /,不是空格,不是 tag_name[0])
|
342
|
+
self.state = "TEXT"
|
343
|
+
current_char_processed = True
|
344
|
+
# 状态: 正在匹配标签名
|
345
|
+
elif self.index < tag_name_len:
|
346
|
+
if self.tag_name[self.index] == char:
|
347
|
+
self.index += 1
|
348
|
+
# 允许在标签名匹配过程中遇到空格,视为属性或无效字符处理
|
349
|
+
elif char.isspace():
|
350
|
+
# 遇到空格,表示标签名已结束,进入属性/结束符处理
|
351
|
+
# 将 index 设置为 tag_name_len 以便后续逻辑处理
|
352
|
+
# 但前提是当前 index 确实匹配到了 tag_name
|
353
|
+
# 如果是 <t hink> 这种情况,这里会失败
|
354
|
+
# 为了简化,我们不允许标签名内部有空格,如果需要,逻辑会更复杂
|
355
|
+
# 因此,如果这里遇到空格但 index < tag_name_len,视为无效
|
356
|
+
self.state = "TEXT"
|
357
|
+
current_char_processed = True
|
358
|
+
else:
|
359
|
+
# 字符不匹配标签名
|
360
|
+
self.state = "TEXT"
|
361
|
+
current_char_processed = True
|
362
|
+
# 状态: 标签名已完全匹配 (self.index == tag_name_len)
|
363
|
+
else: # self.index >= tag_name_len (实际是 ==)
|
364
|
+
if char == ">":
|
365
|
+
# 找到了开始标签的结束符
|
366
|
+
self.state = "TEXT"
|
367
|
+
self.depth += 1
|
368
|
+
self.matched = True
|
369
|
+
self.cached = [] # 清空缓存,丢弃 <tag ...>
|
370
|
+
elif char.isspace():
|
371
|
+
# 忽略标签名后的空格
|
372
|
+
pass # 保持在 TAG_OPEN 状态,等待 > 或属性
|
373
|
+
else:
|
374
|
+
# 字符是属性的一部分,忽略它,继续等待 '>'
|
375
|
+
pass # 保持在 TAG_OPEN 状态
|
376
|
+
|
377
|
+
elif self.state == "TAG_CLOSE":
|
378
|
+
self.cached.append(char)
|
379
|
+
current_char_processed = True # 默认设为 True
|
380
|
+
|
381
|
+
tag_name_len = len(self.tag_name)
|
382
|
+
|
383
|
+
# 状态: 刚进入 </ 之后
|
384
|
+
if self.index == 0:
|
385
|
+
if char.isspace():
|
386
|
+
# 跳过 </ 后的空格
|
387
|
+
pass # index 保持 0
|
388
|
+
elif char == self.tag_name[0]:
|
389
|
+
# 开始匹配标签名
|
390
|
+
self.index = 1
|
391
|
+
else:
|
392
|
+
# 无效闭合标签 (不是空格,不是 tag_name[0])
|
393
|
+
self.state = "TEXT"
|
394
|
+
current_char_processed = True
|
395
|
+
# 状态: 正在匹配标签名
|
396
|
+
elif self.index < tag_name_len:
|
397
|
+
if self.tag_name[self.index] == char:
|
398
|
+
self.index += 1
|
399
|
+
else:
|
400
|
+
# 字符不匹配标签名
|
401
|
+
self.state = "TEXT"
|
402
|
+
current_char_processed = True
|
403
|
+
# 状态: 标签名已完全匹配 (self.index == tag_name_len)
|
404
|
+
else: # self.index == tag_name_len
|
405
|
+
if char == ">":
|
406
|
+
# 找到了 '>'
|
407
|
+
was_inside_tag = self.depth > 0
|
408
|
+
self.state = "TEXT" # 无论如何都回到 TEXT 状态
|
409
|
+
|
410
|
+
if was_inside_tag:
|
411
|
+
# 确实在标签内部,正常处理闭合标签
|
412
|
+
self.depth -= 1
|
413
|
+
self.matched = self.depth > 0
|
414
|
+
self.cached = [] # 清空缓存,丢弃 </tag>
|
415
|
+
# current_char_processed 保持 True
|
416
|
+
else:
|
417
|
+
# 不在标签内部,这是一个无效/意外的闭合标签
|
418
|
+
# 将其视为普通文本,但阻止最后的 > 被添加到缓存
|
419
|
+
# 保留 cached 中已有的 '</tag' 部分,它们将在下次 collect 时作为文本处理
|
420
|
+
current_char_processed = True # 标记 '>' 已处理,防止循环末尾再次添加
|
421
|
+
|
422
|
+
elif char.isspace():
|
423
|
+
# 允许 </tag >, 继续等待 '>'
|
424
|
+
pass # 保持在 TAG_CLOSE 状态, current_char_processed 保持 True
|
425
|
+
else:
|
426
|
+
# 闭合标签名后出现非空格、非 > 的字符
|
427
|
+
self.state = "TEXT"
|
428
|
+
current_char_processed = True
|
429
|
+
|
430
|
+
# 如果当前字符未被状态机逻辑处理(即应视为普通文本)
|
431
|
+
if not current_char_processed:
|
432
|
+
# 确保状态是 TEXT
|
433
|
+
if self.state != "TEXT":
|
434
|
+
# 如果之前在尝试匹配标签但失败了,缓存的内容应视为文本
|
435
|
+
self.state = "TEXT"
|
436
|
+
|
437
|
+
self.cached.append(char)
|
438
|
+
|
439
|
+
self.pointer += 1
|
440
|
+
|
441
|
+
# 在处理完整个 chunk 后,如果状态是 TEXT,收集剩余缓存
|
442
|
+
if self.state == "TEXT":
|
443
|
+
self._collect()
|
444
|
+
|
445
|
+
|
446
|
+
def final(self, chunk: Optional[str] = None) -> List[Union[XmlMatcherResult, R]]:
|
447
|
+
"""处理最后一块数据并返回所有结果"""
|
448
|
+
if chunk:
|
449
|
+
self._update(chunk)
|
450
|
+
# 确保所有剩余缓存都被收集
|
451
|
+
# 即使状态不是 TEXT,也需要收集,以防有未闭合的标签等情况
|
452
|
+
self._collect()
|
453
|
+
return self._pop()
|
454
|
+
|
455
|
+
def update(self, chunk: str) -> List[Union[XmlMatcherResult, R]]:
|
456
|
+
"""处理一块数据并返回当前处理的结果"""
|
457
|
+
self._update(chunk)
|
458
|
+
return self._pop()
|
459
|
+
|
460
|
+
def parse_function_xml(xml_content: str) -> Dict[str, Any]:
|
461
|
+
"""
|
462
|
+
解析XML格式的函数调用信息,转换为字典格式
|
463
|
+
|
464
|
+
参数:
|
465
|
+
xml_content: 包含函数调用的XML字符串
|
466
|
+
|
467
|
+
返回:
|
468
|
+
包含函数名和参数的字典
|
469
|
+
"""
|
470
|
+
# 首先,找出根标签(函数名)
|
471
|
+
# function_matcher = XmlMatcher[XmlMatcherResult]("", position=0)
|
472
|
+
# results = function_matcher.final(xml_content)
|
473
|
+
|
474
|
+
# 找到第一个匹配的标签
|
475
|
+
function_name = ""
|
476
|
+
function_content = ""
|
477
|
+
|
478
|
+
# 寻找第一个开始标签
|
479
|
+
tag_start = xml_content.find("<")
|
480
|
+
if tag_start != -1:
|
481
|
+
tag_end = xml_content.find(">", tag_start)
|
482
|
+
if tag_end != -1:
|
483
|
+
# 提取标签名(函数名)
|
484
|
+
tag_content = xml_content[tag_start+1:tag_end].strip()
|
485
|
+
# 处理可能有属性的情况
|
486
|
+
function_name = tag_content.split()[0] if " " in tag_content else tag_content
|
487
|
+
|
488
|
+
# 使用XmlMatcher提取该函数标签内的内容
|
489
|
+
content_matcher = XmlMatcher[XmlMatcherResult](function_name)
|
490
|
+
match_results = content_matcher.final(xml_content)
|
491
|
+
|
492
|
+
for result in match_results:
|
493
|
+
if result.matched:
|
494
|
+
function_content = result.data
|
495
|
+
break
|
496
|
+
|
497
|
+
# 如果没有找到函数名或内容,返回空结果
|
498
|
+
if not function_name or not function_content:
|
499
|
+
return {'function_name': '', 'parameter': {}}
|
500
|
+
|
501
|
+
# 解析参数
|
502
|
+
parameters = {}
|
503
|
+
lines = function_content.strip().split('\n')
|
504
|
+
current_param = None
|
505
|
+
current_value = []
|
506
|
+
|
507
|
+
for line in lines:
|
508
|
+
line = line.strip()
|
509
|
+
if line.startswith('<') and '>' in line:
|
510
|
+
# 新参数开始
|
511
|
+
if current_param and current_value:
|
512
|
+
# 保存之前的参数
|
513
|
+
parameters[current_param] = '\n'.join(current_value).strip()
|
514
|
+
current_value = []
|
515
|
+
|
516
|
+
# 提取参数名
|
517
|
+
param_start = line.find('<') + 1
|
518
|
+
param_end = line.find('>', param_start)
|
519
|
+
if param_end != -1:
|
520
|
+
param = line[param_start:param_end]
|
521
|
+
# 检查是否是闭合标签
|
522
|
+
if param.startswith('/'):
|
523
|
+
if param[1:] == current_param:
|
524
|
+
current_param = None
|
525
|
+
else:
|
526
|
+
current_param = param
|
527
|
+
# 检查是否在同一行有值
|
528
|
+
rest = line[param_end+1:]
|
529
|
+
if rest and not rest.startswith('</'):
|
530
|
+
current_value.append(rest)
|
531
|
+
elif current_param:
|
532
|
+
# 继续收集当前参数的值
|
533
|
+
current_value.append(line)
|
534
|
+
|
535
|
+
# 处理最后一个参数
|
536
|
+
if current_param and current_value:
|
537
|
+
parameters[current_param] = '\n'.join(current_value).strip()
|
538
|
+
|
539
|
+
# 清理参数值中可能的结束标签
|
540
|
+
for param, value in parameters.items():
|
541
|
+
end_tag = f'</{param}>'
|
542
|
+
if value.endswith(end_tag):
|
543
|
+
parameters[param] = value[:-len(end_tag)].strip()
|
544
|
+
|
545
|
+
return {
|
546
|
+
'function_name': function_name,
|
547
|
+
'parameter': parameters
|
548
|
+
}
|
549
|
+
|
234
550
|
if __name__ == "__main__":
|
235
551
|
os.system("clear")
|
@@ -3,7 +3,7 @@ aient/core/.git,sha256=lrAcW1SxzRBUcUiuKL5tS9ykDmmTXxyLP3YYU-Y-Q-I,45
|
|
3
3
|
aient/core/__init__.py,sha256=NxjebTlku35S4Dzr16rdSqSTWUvvwEeACe8KvHJnjPg,34
|
4
4
|
aient/core/log_config.py,sha256=kz2_yJv1p-o3lUQOwA3qh-LSc3wMHv13iCQclw44W9c,274
|
5
5
|
aient/core/models.py,sha256=8MsuiYHBHVR5UMQ_cNLkvntoxalS7NpVwaNwHA0iZmk,7379
|
6
|
-
aient/core/request.py,sha256
|
6
|
+
aient/core/request.py,sha256=-nyFwGM86LB8Zn6ScRJvAbkJ9LPCHjgg51tO_edAIZ4,48422
|
7
7
|
aient/core/response.py,sha256=7s1Jil0E5nnbL9xQldcjHIqSp0MFeWQo9mNX_iAuvSk,25954
|
8
8
|
aient/core/utils.py,sha256=i9ZwyywBLIhRM0fNmFSD3jF3dBL5QqVMOtSlG_ddv-I,24101
|
9
9
|
aient/core/test/test_base_api.py,sha256=CjfFzMG26r8C4xCPoVkKb3Ac6pp9gy5NUCbZJHoSSsM,393
|
@@ -12,7 +12,7 @@ aient/core/test/test_payload.py,sha256=8jBiJY1uidm1jzL-EiK0s6UGmW9XkdsuuKFGrwFhF
|
|
12
12
|
aient/models/__init__.py,sha256=ouNDNvoBBpIFrLsk09Q_sq23HR0GbLAKfGLIFmfEuXE,219
|
13
13
|
aient/models/audio.py,sha256=kRd-8-WXzv4vwvsTGwnstK-WR8--vr9CdfCZzu8y9LA,1934
|
14
14
|
aient/models/base.py,sha256=Loyt2F2WrDMBbK-sdmTtgkLVtdUXxK5tg4qoI6nc0Xo,7527
|
15
|
-
aient/models/chatgpt.py,sha256=
|
15
|
+
aient/models/chatgpt.py,sha256=UcadvLiBh4a3VHEMRxb4hZWXqZ899QP8Ii81BRegmQ4,38604
|
16
16
|
aient/models/claude.py,sha256=thK9P8qkaaoUN3OOJ9Shw4KDs-pAGKPoX4FOPGFXva8,28597
|
17
17
|
aient/models/duckduckgo.py,sha256=1l7vYCs9SG5SWPCbcl7q6pCcB5AUF_r-a4l9frz3Ogo,8115
|
18
18
|
aient/models/gemini.py,sha256=chGLc-8G_DAOxr10HPoOhvVFW1RvMgHd6mt--VyAW98,14730
|
@@ -28,9 +28,9 @@ aient/plugins/today.py,sha256=btnXJNqWorJDKPvH9PBTdHaExpVI1YPuSAeRrq-fg9A,667
|
|
28
28
|
aient/plugins/websearch.py,sha256=yiBzqXK5X220ibR-zko3VDsn4QOnLu1k6E2YOygCeTQ,15185
|
29
29
|
aient/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
30
30
|
aient/utils/prompt.py,sha256=UcSzKkFE4-h_1b6NofI6xgk3GoleqALRKY8VBaXLjmI,11311
|
31
|
-
aient/utils/scripts.py,sha256=
|
32
|
-
aient-1.0.
|
33
|
-
aient-1.0.
|
34
|
-
aient-1.0.
|
35
|
-
aient-1.0.
|
36
|
-
aient-1.0.
|
31
|
+
aient/utils/scripts.py,sha256=7QCR7iQcWtwLgrhRFxQzPeb20N0kB6-T9MxDoSpTsjk,21573
|
32
|
+
aient-1.0.39.dist-info/licenses/LICENSE,sha256=XNdbcWldt0yaNXXWB_Bakoqnxb3OVhUft4MgMA_71ds,1051
|
33
|
+
aient-1.0.39.dist-info/METADATA,sha256=PPeUAD0T4V8KtmWiiVZ5dPjScpY9HbWA4gAdkKkACk0,4986
|
34
|
+
aient-1.0.39.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
35
|
+
aient-1.0.39.dist-info/top_level.txt,sha256=3oXzrP5sAVvyyqabpeq8A2_vfMtY554r4bVE-OHBrZk,6
|
36
|
+
aient-1.0.39.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|