lionagi 0.2.5__py3-none-any.whl → 0.2.7__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,6 +26,8 @@ load_dotenv()
26
26
 
27
27
  _oai_price_map = {
28
28
  "gpt-4o": (5, 15),
29
+ "gpt-4o-2024-08-06": (2.5, 10),
30
+ "gpt-4o-mini": (0.15, 0.6),
29
31
  "gpt-4-turbo": (10, 30),
30
32
  "gpt-3.5-turbo": (0.5, 1.5),
31
33
  }
@@ -322,6 +324,38 @@ class iModel:
322
324
  node.add_field("embedding", embed["data"][0]["embedding"])
323
325
  node._meta_insert("embedding_meta", payload)
324
326
 
327
+ async def format_structure(
328
+ self,
329
+ data: str | dict,
330
+ json_schema: dict | str = None,
331
+ request_fields: dict | list = None,
332
+ **kwargs,
333
+ ) -> dict:
334
+ if json_schema:
335
+ kwargs["response_format"] = {
336
+ "type": "json_schema",
337
+ "json_schema": json_schema,
338
+ }
339
+ kwargs["model"] = kwargs.pop("model", "gpt-4o-mini")
340
+ if not request_fields and not json_schema:
341
+ raise ValueError("Either request_fields or json_schema must be provided")
342
+ request_fields = request_fields or json_schema["properties"]
343
+
344
+ messages = [
345
+ {
346
+ "role": "system",
347
+ "content": "You are a helpful json formatting assistant.",
348
+ },
349
+ {
350
+ "role": "user",
351
+ "content": f"can you please format the given data into given json schema?"
352
+ f"--- data --- {data} |||| ----json fields required --- {request_fields}",
353
+ },
354
+ ]
355
+
356
+ result = await self.call_chat_completion(messages, **kwargs)
357
+ return result["choices"][0]["message"]["content"]
358
+
325
359
  def to_dict(self):
326
360
  """
327
361
  Converts the model instance to a dictionary representation.
@@ -58,7 +58,7 @@ class Branch(Node, DirectiveMixin):
58
58
  messages: Pile = Field(None)
59
59
  progress: Progression = Field(None)
60
60
  tool_manager: ToolManager = Field(None)
61
- system: System = Field(None)
61
+ system: System | None = Field(None)
62
62
  user: str = Field(None)
63
63
  mailbox: Exchange[Mail] = Field(None)
64
64
  imodel: iModel = Field(None)
@@ -110,14 +110,14 @@ class Branch(Node, DirectiveMixin):
110
110
  system (System): The system message to set.
111
111
  sender (str, optional): The sender of the system message.
112
112
  """
113
- system = system or "You are a helpful assistant."
114
- if len(self.progress) == 0:
115
- self.add_message(system=system, sender=sender)
116
- else:
117
- _msg = System(system=system, sender=sender)
118
- _msg.recipient = self.ln_id
119
- self._remove_system()
120
- self.system = _msg
113
+ if system is not None:
114
+ if len(self.progress) == 0:
115
+ self.add_message(system=system, sender=sender)
116
+ else:
117
+ _msg = System(system=system, sender=sender)
118
+ _msg.recipient = self.ln_id
119
+ self._remove_system()
120
+ self.system = _msg
121
121
 
122
122
  def add_message(
123
123
  self,
@@ -51,6 +51,10 @@ class DirectiveMixin:
51
51
  return_branch=False,
52
52
  images=None,
53
53
  image_path=None,
54
+ template=None,
55
+ verbose=True,
56
+ formatter=None,
57
+ format_kwargs=None,
54
58
  **kwargs,
55
59
  ):
56
60
  """
@@ -114,7 +118,15 @@ class DirectiveMixin:
114
118
  >>> print(result)
115
119
  """
116
120
 
117
- directive = Unit(self, imodel=imodel, rulebook=rulebook)
121
+ directive = Unit(
122
+ self,
123
+ imodel=imodel,
124
+ rulebook=rulebook,
125
+ template=template,
126
+ verbose=verbose,
127
+ formatter=formatter,
128
+ format_kwargs=format_kwargs,
129
+ )
118
130
  if system:
119
131
  self.add_message(system=system)
120
132
 
@@ -174,7 +186,10 @@ class DirectiveMixin:
174
186
  directive=None,
175
187
  images=None,
176
188
  image_path=None,
177
- verbose=False,
189
+ template=None,
190
+ verbose=True,
191
+ formatter=None,
192
+ format_kwargs=None,
178
193
  **kwargs,
179
194
  ):
180
195
  """
@@ -220,7 +235,14 @@ class DirectiveMixin:
220
235
 
221
236
  images = ImageUtil.read_image_to_base64(image_path)
222
237
 
223
- _directive = Unit(self, imodel=imodel, rulebook=rulebook, verbose=verbose)
238
+ _directive = Unit(
239
+ self,
240
+ imodel=imodel,
241
+ rulebook=rulebook,
242
+ verbose=verbose,
243
+ formatter=formatter,
244
+ format_kwargs=format_kwargs,
245
+ )
224
246
 
225
247
  idx = len(self.progress)
226
248
  if directive and isinstance(directive, str):
@@ -232,6 +254,7 @@ class DirectiveMixin:
232
254
  reason=reason,
233
255
  confidence=confidence,
234
256
  images=images,
257
+ template=template,
235
258
  **kwargs,
236
259
  )
237
260
 
@@ -269,6 +292,7 @@ class DirectiveMixin:
269
292
  plan_num_step=plan_num_step,
270
293
  predict_num_sentences=predict_num_sentences,
271
294
  images=images,
295
+ template=template,
272
296
  **kwargs,
273
297
  )
274
298
 
lionagi/core/unit/unit.py CHANGED
@@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  """
16
16
 
17
+ from typing import Callable
17
18
  from lionagi.libs.ln_convert import strip_lower
18
19
  from lionagi.libs.ln_func_call import rcall
19
20
  from lionagi.core.collections.abc import Directive
@@ -40,7 +41,14 @@ class Unit(Directive, DirectiveMixin):
40
41
  default_template = UnitForm
41
42
 
42
43
  def __init__(
43
- self, branch, imodel: iModel = None, template=None, rulebook=None, verbose=False
44
+ self,
45
+ branch,
46
+ imodel: iModel = None,
47
+ template=None,
48
+ rulebook=None,
49
+ verbose=False,
50
+ formatter: Callable = None,
51
+ format_kwargs: dict = {},
44
52
  ) -> None:
45
53
  self.branch = branch
46
54
  if imodel and isinstance(imodel, iModel):
@@ -49,7 +57,11 @@ class Unit(Directive, DirectiveMixin):
49
57
  else:
50
58
  self.imodel = branch.imodel
51
59
  self.form_template = template or self.default_template
52
- self.validator = Validator(rulebook=rulebook) if rulebook else Validator()
60
+ rule_config = {"formatter": formatter, "format_kwargs": format_kwargs}
61
+ if rulebook:
62
+ rule_config["rulebook"] = rulebook
63
+
64
+ self.validator = Validator(**rule_config)
53
65
  self.verbose = verbose
54
66
 
55
67
  async def chat(
@@ -71,6 +83,8 @@ class Unit(Directive, DirectiveMixin):
71
83
  clear_messages=False,
72
84
  use_annotation=True,
73
85
  return_branch=False,
86
+ formatter=None,
87
+ format_kwargs={},
74
88
  **kwargs,
75
89
  ):
76
90
  """
@@ -119,6 +133,8 @@ class Unit(Directive, DirectiveMixin):
119
133
  clear_messages=clear_messages,
120
134
  use_annotation=use_annotation,
121
135
  return_branch=return_branch,
136
+ formatter=formatter,
137
+ format_kwargs=format_kwargs,
122
138
  **kwargs,
123
139
  )
124
140
 
@@ -257,7 +257,6 @@ class DirectiveMixin(ABC):
257
257
  form: Form = None,
258
258
  return_form: bool = True,
259
259
  strict: bool = False,
260
- rulebook: Any = None,
261
260
  use_annotation: bool = True,
262
261
  template_name: str = None,
263
262
  costs=None,
@@ -274,7 +273,6 @@ class DirectiveMixin(ABC):
274
273
  form: Form data.
275
274
  return_form: Flag indicating if form should be returned.
276
275
  strict: Flag indicating if strict validation should be applied.
277
- rulebook: Rulebook instance for validation.
278
276
  use_annotation: Flag indicating if annotations should be used.
279
277
  template_name: Template name for form.
280
278
 
@@ -295,8 +293,7 @@ class DirectiveMixin(ABC):
295
293
  response_ = self._process_model_response(_msg, requested_fields)
296
294
 
297
295
  if form:
298
- validator = Validator(rulebook=rulebook) if rulebook else self.validator
299
- form = await validator.validate_response(
296
+ form = await self.validator.validate_response(
300
297
  form=form,
301
298
  response=response_,
302
299
  strict=strict,
@@ -332,7 +329,6 @@ class DirectiveMixin(ABC):
332
329
  invoke_tool: bool = True,
333
330
  return_form: bool = True,
334
331
  strict: bool = False,
335
- rulebook: Any = None,
336
332
  imodel: Any = None,
337
333
  use_annotation: bool = True,
338
334
  branch: Any = None,
@@ -356,7 +352,6 @@ class DirectiveMixin(ABC):
356
352
  invoke_tool: Flag indicating if tools should be invoked.
357
353
  return_form: Flag indicating if form should be returned.
358
354
  strict: Flag indicating if strict validation should be applied.
359
- rulebook: Rulebook instance for validation.
360
355
  imodel: Model instance.
361
356
  use_annotation: Flag indicating if annotations should be used.
362
357
  branch: Branch instance.
@@ -400,9 +395,8 @@ class DirectiveMixin(ABC):
400
395
  form=form,
401
396
  return_form=return_form,
402
397
  strict=strict,
403
- rulebook=rulebook,
404
398
  use_annotation=use_annotation,
405
- costs=imodel.costs,
399
+ costs=imodel.costs or (0, 0),
406
400
  )
407
401
 
408
402
  return out_, branch if return_branch else out_
@@ -421,13 +415,14 @@ class DirectiveMixin(ABC):
421
415
  invoke_tool=True,
422
416
  return_form=True,
423
417
  strict=False,
424
- rulebook=None,
425
418
  imodel=None,
426
419
  images: Optional[str] = None,
427
420
  clear_messages=False,
428
421
  use_annotation=True,
429
422
  timeout: float = None,
430
423
  return_branch=False,
424
+ formatter=None,
425
+ format_kwargs={},
431
426
  **kwargs,
432
427
  ):
433
428
  """
@@ -470,13 +465,14 @@ class DirectiveMixin(ABC):
470
465
  invoke_tool=invoke_tool,
471
466
  return_form=return_form,
472
467
  strict=strict,
473
- rulebook=rulebook,
474
468
  imodel=imodel,
475
469
  use_annotation=use_annotation,
476
470
  timeout=timeout,
477
471
  branch=branch,
478
472
  clear_messages=clear_messages,
479
473
  return_branch=return_branch,
474
+ formatter=formatter,
475
+ format_kwargs=format_kwargs,
480
476
  **kwargs,
481
477
  )
482
478
 
@@ -609,7 +605,9 @@ class DirectiveMixin(ABC):
609
605
  clear_messages=False,
610
606
  return_branch=False,
611
607
  images: Optional[str] = None,
612
- verbose=None,
608
+ verbose=True,
609
+ formatter=None,
610
+ format_kwargs=None,
613
611
  **kwargs,
614
612
  ):
615
613
  """
@@ -14,10 +14,12 @@ See the License for the specific language governing permissions and
14
14
  limitations under the License.
15
15
  """
16
16
 
17
- from typing import Any, Dict, List, Union
17
+ import asyncio
18
+ from typing import Any, Dict, List, Union, Callable
18
19
  from lionagi.libs import SysUtil
19
20
  from lionagi.libs.ln_func_call import lcall
20
21
  from lionagi.core.collections.abc import FieldError
22
+ from lionagi.core.collections.model import iModel
21
23
  from ..rule.base import Rule
22
24
  from ..rule._default import DEFAULT_RULES
23
25
  from ..rule.rulebook import RuleBook
@@ -56,6 +58,8 @@ class Validator:
56
58
  order: List[str] = None,
57
59
  init_config: Dict[str, Dict] = None,
58
60
  active_rules: Dict[str, Rule] = None,
61
+ formatter: Callable = None,
62
+ format_kwargs: dict = {},
59
63
  ):
60
64
  """
61
65
  Initialize the Validator.
@@ -75,6 +79,8 @@ class Validator:
75
79
  )
76
80
  self.active_rules: Dict[str, Rule] = active_rules or self._initiate_rules()
77
81
  self.validation_log = []
82
+ self.formatter = formatter
83
+ self.format_kwargs = format_kwargs
78
84
 
79
85
  def _initiate_rules(self) -> Dict[str, Rule]:
80
86
  """
@@ -207,9 +213,16 @@ class Validator:
207
213
  if len(form.requested_fields) == 1:
208
214
  response = {form.requested_fields[0]: response}
209
215
  else:
210
- raise ValueError(
211
- "Response is a string, but form has multiple fields to be filled"
212
- )
216
+ if self.formatter:
217
+ if asyncio.iscoroutinefunction(self.formatter):
218
+ response = await self.formatter(response, **self.format_kwargs)
219
+ print("formatter used")
220
+ else:
221
+ response = self.formatter(response, **self.format_kwargs)
222
+ print("formatter used")
223
+
224
+ if not isinstance(response, dict):
225
+ raise ValueError(f"The form response format is invalid for filling.")
213
226
 
214
227
  dict_ = {}
215
228
  for k, v in response.items():
lionagi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.5"
1
+ __version__ = "0.2.7"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lionagi
3
- Version: 0.2.5
3
+ Version: 0.2.7
4
4
  Summary: Towards automated general intelligence.
5
5
  Author: HaiyangLi
6
6
  Author-email: Haiyang Li <ocean@lionagi.ai>
@@ -237,7 +237,7 @@ Requires-Dist: boto3 >=1.34.131
237
237
  ### an AGentic Intelligence Operating System
238
238
 
239
239
  ```
240
- pip install lionagi==0.2.5
240
+ pip install lionagi==0.2.6
241
241
  ```
242
242
 
243
243
  **Powerful Intelligent Workflow Automation**
@@ -1,5 +1,5 @@
1
1
  lionagi/__init__.py,sha256=amQal6CUIv4QDI4Qmb0M5qwTbn3_F430Wl5vaSNG6-U,1952
2
- lionagi/version.py,sha256=Xsa3ayOMVkhUWm4t06YeyHE0apjpZefxLH4ylp0CDtU,22
2
+ lionagi/version.py,sha256=XHypfHSPdgXFKmOdoewn7czU670gt8InhHhzlP5j_aA,22
3
3
  lionagi/core/__init__.py,sha256=Il5Q9ATdX8yXqVxtP_nYqUhExzxPC_qk_WXQ_4h0exg,16
4
4
  lionagi/core/_setting/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  lionagi/core/_setting/_setting.py,sha256=p23fHtrzIZlQ8s8CDZICn8C6k7mdB_088nIDx19JaqM,1907
@@ -23,7 +23,7 @@ lionagi/core/collections/__init__.py,sha256=5374e0qHH75IUvW-xA3Dte25N_oc_YXjtu7e
23
23
  lionagi/core/collections/_logger.py,sha256=_jwZe6BsRaWB2YkHwG01jmiudJkoi5u90Ry3KKa9T-o,12104
24
24
  lionagi/core/collections/exchange.py,sha256=Skx2al0PtNkzdaApb8DdbOO0ukC19kSQnlskHpAHJHw,4832
25
25
  lionagi/core/collections/flow.py,sha256=0tBeVJhENXjVFjtOlrEHXvI4q-rgTyD-kcE7X29AqDE,13189
26
- lionagi/core/collections/model.py,sha256=RQYuvZachSYJi8owQ44GPSZXV22l-KdWqJAL40CG2PE,14846
26
+ lionagi/core/collections/model.py,sha256=U9yFhQ31NH24HwJjnnRxOfZcnUWq8Vuk_iF0r8SZc5A,16079
27
27
  lionagi/core/collections/pile.py,sha256=MF2G846TolIiKZkY0mjSOvD7Bc3__Fb_z-WiiLG1lbM,29444
28
28
  lionagi/core/collections/progression.py,sha256=eDhSbsQWb9TVsNExaJAN27tjoyb6QEKWPxBZKUbNbs0,7295
29
29
  lionagi/core/collections/util.py,sha256=JRu_gCDYopqIUByEtJgnJNkeoWnhge7XbSFejrdbIec,1962
@@ -82,8 +82,8 @@ lionagi/core/rule/rulebook.py,sha256=HlJCIjhsRB0yJs-uF85aK9bJasCDI0K845UGmymzD9Q
82
82
  lionagi/core/rule/string.py,sha256=8nSxEhHUFs-gWM1MW5fiNuDP1Yd_IIZ2ipBVphgCmQ0,1487
83
83
  lionagi/core/rule/util.py,sha256=qqtUqt4BL_sikW2XZ73NDzb3p-Awu4za_2B5mZvzFdA,1042
84
84
  lionagi/core/session/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
85
- lionagi/core/session/branch.py,sha256=6ySBqEZHYbQ1AKJmcoBtU9MwF5WT5wAr3z2NB6TF8gg,14761
86
- lionagi/core/session/directive_mixin.py,sha256=SgLFQwZyqnP6pCoZU1YBJuO6olnSBKZ6FIfl-Je3uVQ,11724
85
+ lionagi/core/session/branch.py,sha256=338N-jw-AfnjksYFo2WiLIeXdzxOYJ_qZBxMuk-U8bU,14769
86
+ lionagi/core/session/directive_mixin.py,sha256=vCoOIA_AYEH7M1ptDBUaOtSuxC5KQSAnsKn9X-LpjFs,12275
87
87
  lionagi/core/session/session.py,sha256=uESwIyGfRrX8Ii03-QIQYUlQKR7lsJWREdSZrHxfNW4,11012
88
88
  lionagi/core/structure/__init__.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
89
89
  lionagi/core/structure/chain.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
@@ -92,9 +92,9 @@ lionagi/core/structure/graph.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzI
92
92
  lionagi/core/structure/tree.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
93
93
  lionagi/core/unit/__init__.py,sha256=cxASNHNw2wK-SO9a4FQTjKDOOpT3HRE_qFD5GEvHdbQ,88
94
94
  lionagi/core/unit/parallel_unit.py,sha256=DB5PjGMin2PkXc4qR7u6zEMxkj8WVgtSfdMoPhSby0A,9332
95
- lionagi/core/unit/unit.py,sha256=V-0qOUtW5v5XHNUGJl9aE1j8fxYVWwLulrxySkN814w,12986
95
+ lionagi/core/unit/unit.py,sha256=hnXSjHPc9TXOfPv-sUV1T8LIUhmjXODpIZr9Sj9cGwE,13364
96
96
  lionagi/core/unit/unit_form.py,sha256=1WDBXDprnsyz8OEbDH7LLRceldhvZHmswVoZb1CV80E,11580
97
- lionagi/core/unit/unit_mixin.py,sha256=E8GY7eAjtvlfYW4Thpd-XoOeAZMLYC13HMyC2erCueE,39314
97
+ lionagi/core/unit/unit_mixin.py,sha256=-Jy3KxhETyQYGUxo2xZQByHjGuckzeHLU1CaMknwu5k,39163
98
98
  lionagi/core/unit/util.py,sha256=GqErzoWlUeSBtl3qcjqMONJoNK7i1DYJ_S3JW6MnEp8,1994
99
99
  lionagi/core/unit/template/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
100
  lionagi/core/unit/template/action.py,sha256=AETiRQKDvjB-EEyi-i6u3UqQ8650HbDkUaSSNxQJ8P0,2791
@@ -104,7 +104,7 @@ lionagi/core/unit/template/predict.py,sha256=LdsKgoXs-yQIb6VfFD08CphAn33SJWUlLF8
104
104
  lionagi/core/unit/template/score.py,sha256=vTiSzL80YDQERVEQT-VNc_wKWbVJyLfvBa2DSexKyLg,4368
105
105
  lionagi/core/unit/template/select.py,sha256=n9u1Yer_fWPYZDzAnlYpSECo_hk7B0gTaEGSta6i8is,3604
106
106
  lionagi/core/validator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
107
- lionagi/core/validator/validator.py,sha256=ngThQTzNSOa6N0mKrAQuhwM_gb_IWhF58OefOyUjTK8,12012
107
+ lionagi/core/validator/validator.py,sha256=ohlaNxxoi7KCY_1BIyTt03JegpqmGIhuqnIdtHL2nDE,12618
108
108
  lionagi/core/work/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
109
  lionagi/core/work/work.py,sha256=oVbx0b8arvXSjDZa2Rs1s37_Fiue6gbR0Tt4oL7Dzkk,2532
110
110
  lionagi/core/work/work_edge.py,sha256=o6bCDjQIfBjnnpbd7ZVNLGuRQgmvLDwPah58TaTK0eU,3408
@@ -251,8 +251,8 @@ lionagi/tests/test_core/test_structure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
251
251
  lionagi/tests/test_core/test_structure/test_base_structure.py,sha256=qsaYP745fFIst5ZNiPFb9-ATScLyUFqQ5UQzyyBgJPM,9388
252
252
  lionagi/tests/test_core/test_structure/test_graph.py,sha256=hLsTZmZMs9vCZW-KiOwYY3npk6WxaVU6zZSA9-ltDvQ,2162
253
253
  lionagi/tests/test_core/test_structure/test_tree.py,sha256=PvMJXDsNPpJFgEQCan-5Q5JREgMrBOpYIaWcwHd-WDY,1944
254
- lionagi-0.2.5.dist-info/LICENSE,sha256=VXFWsdoN5AAknBCgFqQNgPWYx7OPp-PFEP961zGdOjc,11288
255
- lionagi-0.2.5.dist-info/METADATA,sha256=svScDN5_cqlfWuaNVwMnRnTUdf5Sx8MY4f1hk03HXjc,16276
256
- lionagi-0.2.5.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
257
- lionagi-0.2.5.dist-info/top_level.txt,sha256=szvch_d2jE1Lu9ZIKsl26Ll6BGfYfbOgt5lm-UpFSo4,8
258
- lionagi-0.2.5.dist-info/RECORD,,
254
+ lionagi-0.2.7.dist-info/LICENSE,sha256=VXFWsdoN5AAknBCgFqQNgPWYx7OPp-PFEP961zGdOjc,11288
255
+ lionagi-0.2.7.dist-info/METADATA,sha256=WI8pyy3AHxkvSBmxFFQKtYGoL-tCXEplXj6xU9rzcWs,16276
256
+ lionagi-0.2.7.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
257
+ lionagi-0.2.7.dist-info/top_level.txt,sha256=szvch_d2jE1Lu9ZIKsl26Ll6BGfYfbOgt5lm-UpFSo4,8
258
+ lionagi-0.2.7.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5