lionagi 0.8.2__py3-none-any.whl → 0.8.4__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.
@@ -11,6 +11,8 @@ from lionagi.operatives.types import Instruct
11
11
  from lionagi.service.imodel import iModel
12
12
  from lionagi.utils import copy
13
13
 
14
+ from .utils import ReActAnalysis
15
+
14
16
  if TYPE_CHECKING:
15
17
  from lionagi.session.branch import Branch
16
18
 
@@ -60,11 +62,9 @@ async def ReAct(
60
62
  kwargs_for_operate["actions"] = True
61
63
  kwargs_for_operate["reason"] = True
62
64
 
63
- # We'll pass the refined instruct_dict plus the user's other kwargs
64
- from .utils import ReActAnalysis
65
-
66
65
  # Step 1: Generate initial ReAct analysis
67
66
  analysis: ReActAnalysis = await branch.operate(
67
+ instruct=instruct_dict,
68
68
  response_format=ReActAnalysis,
69
69
  tools=tools,
70
70
  tool_schemas=tool_schemas,
@@ -83,7 +83,7 @@ async def ReAct(
83
83
  while (
84
84
  extension_allowed
85
85
  and analysis.extension_needed
86
- and (extensions if extensions else 1) > 0
86
+ and (extensions if max_extensions else 0) > 0
87
87
  ):
88
88
  new_instruction = None
89
89
  if extensions == max_extensions:
@@ -95,17 +95,13 @@ async def ReAct(
95
95
  extensions=extensions
96
96
  )
97
97
 
98
- # Each expansion uses a fresh copy of instruct_dict + forcibly "reason" + "actions"
99
- expanded_kwargs = copy(instruct_dict)
100
- expanded_kwargs["instruction"] = new_instruction
101
- expanded_kwargs["reason"] = True
102
- expanded_kwargs["actions"] = True
103
-
104
98
  analysis = await branch.operate(
99
+ instruction=new_instruction,
105
100
  response_format=ReActAnalysis,
106
101
  tools=tools,
107
102
  tool_schemas=tool_schemas,
108
- **expanded_kwargs,
103
+ reason=True,
104
+ actions=True,
109
105
  )
110
106
  analyses.append(analysis)
111
107
 
@@ -10,19 +10,19 @@ from pydantic import BaseModel, Field
10
10
  class ReActAnalysis(BaseModel):
11
11
 
12
12
  FIRST_EXT_PROMPT: ClassVar[str] = (
13
- "You are provided with another round to perform reason action to provide an accurate final answer. you have max another {extensions} rounds, set extension_needed to False if you are done and ready to provide final answer."
13
+ "You are provided with additional rounds to perform reason action to provide an accurate final answer. you have max another {extensions} rounds. Pleasen continue."
14
14
  )
15
15
 
16
16
  CONTINUE_EXT_PROMPT: ClassVar[str] = (
17
- "You are provided with another round, you have max another {extensions} rounds"
17
+ "You are provided with another round, you have max another {extensions} rounds. Please continue."
18
18
  )
19
19
 
20
20
  ANSWER_PROMPT: ClassVar[str] = (
21
- "given above reason and actions, please provide final answer to the original user request {instruction}"
21
+ "given above reason and actions, please provide final answer to the original user request:\n\n {instruction}"
22
22
  )
23
23
 
24
24
  analysis: str
25
25
  extension_needed: bool = Field(
26
26
  False,
27
- description="Set to True if more steps are needed to provide an accurate answer. If True, additional rounds are allowed.",
27
+ description="Set to True if more steps are needed to provide an accurate answer. If True, additional rounds are allowed. Typically should be set to true if more actions should be taken or planned to be taken. If false, will proceed to provide final answer next.",
28
28
  )
@@ -5,7 +5,7 @@
5
5
  import asyncio
6
6
  from typing import Any
7
7
 
8
- from pydantic import Field, model_validator
8
+ from pydantic import BaseModel, Field, field_validator, model_validator
9
9
  from typing_extensions import Self
10
10
 
11
11
  from lionagi.protocols.generic.event import Event, EventStatus
@@ -27,12 +27,22 @@ class FunctionCalling(Event):
27
27
  exclude=True,
28
28
  )
29
29
 
30
- arguments: dict[str, Any] = Field(
30
+ arguments: dict[str, Any] | BaseModel = Field(
31
31
  ..., description="Dictionary of arguments to pass to the function"
32
32
  )
33
33
 
34
+ @field_validator("arguments", mode="before")
35
+ def _validate_argument(cls, value):
36
+ if isinstance(value, BaseModel):
37
+ return value.model_dump(exclude_unset=True)
38
+ return value
39
+
34
40
  @model_validator(mode="after")
35
41
  def _validate_strict_tool(self) -> Self:
42
+ if self.func_tool.request_options:
43
+ args: BaseModel = self.func_tool.request_options(**self.arguments)
44
+ self.arguments = args.model_dump(exclude_unset=True)
45
+
36
46
  if self.func_tool.strict_func_call is True:
37
47
  if (
38
48
  not set(self.arguments.keys())
@@ -49,6 +49,11 @@ class Tool(Element):
49
49
  description="Schema describing the function's parameters and structure",
50
50
  )
51
51
 
52
+ request_options: type | None = Field(
53
+ default=None,
54
+ description="Optional Pydantic model for validating the function's input",
55
+ )
56
+
52
57
  preprocessor: Callable[[Any], Any] | None = Field(
53
58
  default=None,
54
59
  description="Optional function for preprocessing inputs before execution",
@@ -88,6 +93,11 @@ class Tool(Element):
88
93
  def _validate_tool_schema(self) -> Self:
89
94
  if self.tool_schema is None:
90
95
  self.tool_schema = function_to_schema(self.func_callable)
96
+ if self.request_options is not None:
97
+ schema_ = self.request_options.model_json_schema()
98
+ schema_.pop("title", None)
99
+ self.tool_schema["function"]["parameters"] = schema_
100
+
91
101
  return self
92
102
 
93
103
  @property
@@ -1,5 +1,4 @@
1
1
  # forms/flow.py
2
- from typing import List
3
2
 
4
3
  from pydantic import BaseModel, ConfigDict, Field
5
4
 
@@ -1,6 +1,6 @@
1
1
  # forms/form.py
2
2
 
3
- from typing import Any, Optional
3
+ from typing import Any
4
4
 
5
5
  from pydantic import ConfigDict, Field, model_validator
6
6
  from typing_extensions import Self
@@ -81,68 +81,121 @@ def format_text_item(item: Any) -> str:
81
81
 
82
82
  def format_text_content(content: dict) -> str:
83
83
  """
84
- Convert a dictionary with keys like 'guidance', 'instruction', 'context', etc.
85
- into a readable text block.
84
+ Convert a content dictionary into a minimal textual summary for LLM consumption.
86
85
 
87
- Args:
88
- content (dict): The content dictionary.
89
-
90
- Returns:
91
- str: A textual summary.
86
+ Emphasizes brevity and clarity:
87
+ - Skips empty or None fields.
88
+ - Bullet-points for lists.
89
+ - Key-value pairs for dicts.
90
+ - Minimal headings for known fields (guidance, instruction, etc.).
92
91
  """
93
- if "plain_content" in content and isinstance(
94
- content["plain_content"], str
95
- ):
96
- return content["plain_content"]
97
92
 
98
- msg = "\n---\n # Task\n"
93
+ if isinstance(content.get("plain_content"), str):
94
+ return content["plain_content"]
99
95
 
100
- for k in [
96
+ lines = []
97
+ # We only want minimal headings for certain known fields:
98
+ known_field_order = [
101
99
  "guidance",
102
100
  "instruction",
103
101
  "context",
104
102
  "tool_schemas",
105
103
  "respond_schema_info",
106
104
  "request_response_format",
107
- ]:
108
- if k in content:
109
- v = content[k]
110
-
111
- if k == "tool_schemas":
112
- if "tools" in v:
113
- v = v["tools"]
114
-
115
- if isinstance(v, list):
116
- z = []
117
- for idx, z_ in enumerate(v):
118
- if isinstance(z_, dict) and "function" in z_:
119
- z.append({f"Tool {idx+1}": z_["function"]})
120
- v = z
121
-
122
- if k == "request_response_format":
123
- k = "response format"
124
-
125
- if v not in [None, [], {}, UNDEFINED]:
126
- if isinstance(v, list):
127
- msg += f"## - **{k}**\n"
128
- for i in v:
129
- if (
130
- len(format_text_item(v).replace("\n", "").strip())
131
- > 0
132
- ):
133
- msg += format_text_item(i).strip()
134
- msg += "\n"
135
- else:
136
- if len(format_text_item(v).replace("\n", "").strip()) > 0:
137
- msg += (
138
- f"## - **{k}**\n{format_text_item(v).strip()}\n\n"
139
- )
140
-
141
- if not msg.endswith("\n\n"):
142
- msg += "\n\n---\n"
105
+ ]
106
+
107
+ # Render known fields in that order
108
+ for field in known_field_order:
109
+ if field in content:
110
+ val = content[field]
111
+ if _is_not_empty(val):
112
+ if field == "request_response_format":
113
+ field = "response format"
114
+ elif field == "respond_schema_info":
115
+ field = "response schema info"
116
+ lines.append(f"\n## {field.upper()}:\n")
117
+ rendered = _render_value(val)
118
+ # Indent or bullet the rendered result if multiline
119
+ # We'll keep it minimal: each line is prefixed with " ".
120
+ lines.extend(
121
+ f" {line}"
122
+ for line in rendered.split("\n")
123
+ if line.strip()
124
+ )
125
+
126
+ # Join all lines into a single string
127
+ return "\n".join(lines).strip()
128
+
129
+
130
+ def _render_value(val) -> str:
131
+ """
132
+ Render an arbitrary value (scalar, list, dict) in minimal form:
133
+ - Lists become bullet points.
134
+ - Dicts become key-value lines.
135
+ - Strings returned directly.
136
+ """
137
+ if isinstance(val, dict):
138
+ return _render_dict(val)
139
+ elif isinstance(val, list):
140
+ return _render_list(val)
143
141
  else:
144
- msg += "---\n"
145
- return msg
142
+ return str(val).strip()
143
+
144
+
145
+ def _render_dict(dct: dict) -> str:
146
+ """
147
+ Minimal bullet list for dictionary items:
148
+ key: rendered subvalue
149
+ """
150
+ lines = []
151
+ for k, v in dct.items():
152
+ if not _is_not_empty(v):
153
+ continue
154
+ subrendered = _render_value(v)
155
+ # Indent subrendered if multiline
156
+ sublines = subrendered.split("\n")
157
+ if len(sublines) == 1:
158
+ if sublines[0].startswith("- "):
159
+ lines.append(f"- {k}: {sublines[0][2:]}")
160
+ else:
161
+ lines.append(f"- {k}: {sublines[0]}")
162
+ else:
163
+ lines.append(f"- {k}:")
164
+ for s in sublines:
165
+ lines.append(f" {s}")
166
+ return "\n".join(lines)
167
+
168
+
169
+ def _render_list(lst: list) -> str:
170
+ """
171
+ Each item in the list gets a bullet. Nested structures are recursed.
172
+ """
173
+ lines = []
174
+ for idx, item in enumerate(lst, 1):
175
+ sub = _render_value(item)
176
+ sublines = sub.split("\n")
177
+ if len(sublines) == 1:
178
+ if sublines[0].startswith("- "):
179
+ lines.append(f"- {sublines[0][2:]}")
180
+ else:
181
+ lines.append(f"- {sublines[0]}")
182
+ else:
183
+ lines.append("-")
184
+ lines.extend(f" {s}" for s in sublines)
185
+ return "\n".join(lines)
186
+
187
+
188
+ def _is_not_empty(x) -> bool:
189
+ """
190
+ Returns True if x is neither None, nor empty string/list/dict.
191
+ """
192
+ if x is None:
193
+ return False
194
+ if isinstance(x, (list, dict)) and not x:
195
+ return False
196
+ if isinstance(x, str) and not x.strip():
197
+ return False
198
+ return True
146
199
 
147
200
 
148
201
  def format_image_content(
lionagi/session/branch.py CHANGED
@@ -345,6 +345,20 @@ class Branch(Element, Communicatable, Relational):
345
345
 
346
346
  return branch_clone
347
347
 
348
+ def register_tools(
349
+ self, tools: FuncTool | list[FuncTool], update: bool = False
350
+ ):
351
+ """
352
+ Registers one or more tools in the ActionManager.
353
+
354
+ Args:
355
+ tools (FuncTool | list[FuncTool]):
356
+ A single tool or a list of tools to register.
357
+ update (bool, optional):
358
+ If `True`, updates existing tools with the same name.
359
+ """
360
+ self._action_manager.register_tools(tools, update=update)
361
+
348
362
  # -------------------------------------------------------------------------
349
363
  # Conversion / Serialization
350
364
  # -------------------------------------------------------------------------
@@ -532,6 +546,33 @@ class Branch(Element, Communicatable, Relational):
532
546
  for key in self.mailbox.pending_ins:
533
547
  self.receive(key)
534
548
 
549
+ def connect(
550
+ self,
551
+ name: str,
552
+ imodel: iModel,
553
+ request_options: type[BaseModel],
554
+ description: str = None,
555
+ update: bool = False,
556
+ ):
557
+ if not update and name in self.tools:
558
+ raise ValueError(f"Tool with name '{name}' already exists.")
559
+
560
+ async def _connect(**kwargs):
561
+ """connect to an api endpoint"""
562
+ api_call = await imodel.invoke(**kwargs)
563
+ self._log_manager.log(Log.create(api_call))
564
+ return api_call.response
565
+
566
+ _connect.__name__ = name
567
+ if description:
568
+ _connect.__doc__ = description
569
+
570
+ tool = Tool(
571
+ func_callable=_connect,
572
+ request_options=request_options,
573
+ )
574
+ self._action_manager.register_tools(tool, update=update)
575
+
535
576
  # -------------------------------------------------------------------------
536
577
  # Dictionary Conversion
537
578
  # -------------------------------------------------------------------------
lionagi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.8.2"
1
+ __version__ = "0.8.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lionagi
3
- Version: 0.8.2
3
+ Version: 0.8.4
4
4
  Summary: An Intelligence Operating System.
5
5
  Author-email: HaiyangLi <quantocean.li@gmail.com>
6
6
  License: Apache License
@@ -4,7 +4,7 @@ lionagi/_errors.py,sha256=wNKdnVQvE_CHEstK7htrrj334RA_vbGcIds-3pUiRkc,455
4
4
  lionagi/_types.py,sha256=9g7iytvSj3UjZxD-jL06_fxuNfgZyWT3Qnp0XYp1wQU,63
5
5
  lionagi/settings.py,sha256=k9zRJXv57TveyfHO3Vr9VGiKrSwlRUUVKt5zf6v9RU4,1627
6
6
  lionagi/utils.py,sha256=QbF4E1PG-BaRcEVH3kJIYCJVNq-oRNoTxjda5k8NYW4,73177
7
- lionagi/version.py,sha256=B7GiO0rd49YwtLYjvPg4lmCZEDlMTonslQKdSImaMJk,22
7
+ lionagi/version.py,sha256=jhHEJFZWhkQDemoZMomBYq-RNrKXknYzUaeIU9A6XsI,22
8
8
  lionagi/libs/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
9
9
  lionagi/libs/parse.py,sha256=tpEbmIRGuHhLCJlUlm6fjmqm_Z6XJLAXGNFHNuk422I,1011
10
10
  lionagi/libs/file/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
@@ -48,9 +48,9 @@ lionagi/operations/__init__.py,sha256=O7nV0tedpUe7_OlUWmCcduGPFtqtzWZcR_SIOnjLsr
48
48
  lionagi/operations/manager.py,sha256=H7UY86PIxvxKdzJY9YVsWyJcqlwLWhVyvm4sYePH_uY,565
49
49
  lionagi/operations/types.py,sha256=LIa68xcyKLVafof-DSFwKtSkneuYPFqrtGyClohYI6o,704
50
50
  lionagi/operations/utils.py,sha256=Twy6L_UFt9JqJFRYuKKTKVZIXsePidNl5ipcYcCbesI,1220
51
- lionagi/operations/ReAct/ReAct.py,sha256=tAZ-3Ya68tVUa112wgOMUJpBVw-RWBSYTfgicbInRuQ,3954
51
+ lionagi/operations/ReAct/ReAct.py,sha256=07F_VhxNnOhOInEZkbY9nT2YiCcnApSibxjz2yAa7Wk,3696
52
52
  lionagi/operations/ReAct/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
53
- lionagi/operations/ReAct/utils.py,sha256=0OhZhoc8QsTsMFo2Jmys1mgpnMwHsldKuLVSbev9uZM,994
53
+ lionagi/operations/ReAct/utils.py,sha256=yBsbaZm3NNb-LhdjdK3jVmxSYbp0enWzl8d09iv8oSo,1099
54
54
  lionagi/operations/_act/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
55
55
  lionagi/operations/_act/act.py,sha256=HBp-sNwNigLDNkuEZqGU_98UCaJXPZsaokkFAXwOMn0,2454
56
56
  lionagi/operations/brainstorm/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
@@ -82,15 +82,15 @@ lionagi/operatives/operative.py,sha256=Pahhjlav-Y1rCYwUZkWNrw6nIOpR9zrqXwuHTYcbj
82
82
  lionagi/operatives/step.py,sha256=DevwisZc2q88ynUiiSu7VBEY2A_G4Q5iRLrVgVLHNJU,9843
83
83
  lionagi/operatives/types.py,sha256=X0Pz0aqVg20D3lfnKOZ0GtLj01M5WoYagVmu_aArkoo,1784
84
84
  lionagi/operatives/action/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
85
- lionagi/operatives/action/function_calling.py,sha256=dHWxnWj-YD2PkYoRO_iOI1dryb8tThuPDX1OMI0y8GM,4631
85
+ lionagi/operatives/action/function_calling.py,sha256=dFNldEuV77quaM2M4VGXPQRhh3yGCAA5WucyipRu13M,5067
86
86
  lionagi/operatives/action/manager.py,sha256=FXfWhQMSFE5qJNZPpgdz4ePvthLafZfnmak2PImCrsc,8824
87
87
  lionagi/operatives/action/request_response_model.py,sha256=mCyKub_WoEttJ_mqLhGoOoPVBQHOhr7sswy_jN6-620,3378
88
- lionagi/operatives/action/tool.py,sha256=CVCNd154XDxRvinmfO_2y72RsCn3UfZEecY7QG2qIjE,5217
88
+ lionagi/operatives/action/tool.py,sha256=39Z2beUUdG0ngoK1r2ynmX4yIiDIyHv_dxb4X53In24,5584
89
89
  lionagi/operatives/action/utils.py,sha256=vUe7Aysuzbg16rAfe2Ttp5QUz5_L6mMedBVAWzGAHwk,4330
90
90
  lionagi/operatives/forms/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
91
91
  lionagi/operatives/forms/base.py,sha256=hitr0eKk7Yts2VfpuBGl0YxpClMJEpsy7xWodhg2AhQ,2720
92
- lionagi/operatives/forms/flow.py,sha256=JRHY_t8yZNN2p_spPvoFG1hD--2YVtAiA8h3hrK7Vt0,2556
93
- lionagi/operatives/forms/form.py,sha256=GJTE_PrlHT_bgWf-zOQaIFdEkx1CUDTzgAyRofPXoOE,2934
92
+ lionagi/operatives/forms/flow.py,sha256=Em0AIiSQT5r45wKjoq57J_wuDZ9fecKZxf6FzmmamQM,2532
93
+ lionagi/operatives/forms/form.py,sha256=j5Mf9DCblJYtN_uCgBhXzE4IkrZHWc7jyzog3tXqeW4,2924
94
94
  lionagi/operatives/forms/report.py,sha256=ZQsM5nDnmF3WdCSurDUBTMI-PEy8yTnRA_uN6tyRneA,1488
95
95
  lionagi/operatives/instruct/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
96
96
  lionagi/operatives/instruct/base.py,sha256=Vw9u3BGzjNRGcPfW1ROr2uCZcZsjrm4WU6491P6ecCI,1895
@@ -149,7 +149,7 @@ lionagi/protocols/messages/action_request.py,sha256=Nsh6Nm6M1BvBOw3TzI5DvSuwH5ld
149
149
  lionagi/protocols/messages/action_response.py,sha256=v5ykwspVEBXYxgFCIgmhdvk8lR3ycxxQdbjwdVLK_w8,5401
150
150
  lionagi/protocols/messages/assistant_response.py,sha256=rWQsvElcUdF9KHkDLTNg_o-uzNl5DTcK066lszvCI0k,6412
151
151
  lionagi/protocols/messages/base.py,sha256=YcOtj-okN5ldbviPsulIDBAFaGRvqpmt7DTfgLYjpwA,2482
152
- lionagi/protocols/messages/instruction.py,sha256=tiznMvDAkuGzsUrh5hkCGKPmxOjZLfr8_zC4Rwzj7J4,19603
152
+ lionagi/protocols/messages/instruction.py,sha256=VvOJ4hpZIngWy1lZM4wrzfYPn8YpXw9wkFTvRfa_XZk,21234
153
153
  lionagi/protocols/messages/manager.py,sha256=QpOIbQ6zVaBzhh7KkMvXdujB05vJK4waSaos14WwG_Q,17370
154
154
  lionagi/protocols/messages/message.py,sha256=ulTjKK4FSWTLFRbMbg8V8cEveKu_fhFnOaAyuVWCXbo,7864
155
155
  lionagi/protocols/messages/system.py,sha256=MX9bR76TbrY3a-d3akocDX3cFSYb9OD6lwP4HqvbFLg,4799
@@ -187,9 +187,9 @@ lionagi/service/providers/openrouter_/chat_completions.py,sha256=MRf4ZbMCgzNIL4g
187
187
  lionagi/service/providers/perplexity_/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
188
188
  lionagi/service/providers/perplexity_/chat_completions.py,sha256=SsDbrtXwQsR4Yu2VMU43KfeS86QWI8UTNhDth5lNWNs,1055
189
189
  lionagi/session/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
190
- lionagi/session/branch.py,sha256=JvErd9YUuGdWyLj37rtKOteSqV0ltn9lg0R2G8GO40c,62539
190
+ lionagi/session/branch.py,sha256=ZLItnjW66__85s0brxhq1LZisjDoVS4HBJSHUpFaxsg,63834
191
191
  lionagi/session/session.py,sha256=po6C7PnM0iu_ISHUo4PBzzQ61HFOgcsAUfPoO--eLak,8987
192
- lionagi-0.8.2.dist-info/METADATA,sha256=lJ_wNrsDsRFOVYHqCc9GbFWe5bFyusOF7-nZW_cMIL4,22819
193
- lionagi-0.8.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
194
- lionagi-0.8.2.dist-info/licenses/LICENSE,sha256=VXFWsdoN5AAknBCgFqQNgPWYx7OPp-PFEP961zGdOjc,11288
195
- lionagi-0.8.2.dist-info/RECORD,,
192
+ lionagi-0.8.4.dist-info/METADATA,sha256=MHgfVuup5176MSrXlfX2B_tQUaiKNdGAjtITrJVLCWY,22819
193
+ lionagi-0.8.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
194
+ lionagi-0.8.4.dist-info/licenses/LICENSE,sha256=VXFWsdoN5AAknBCgFqQNgPWYx7OPp-PFEP961zGdOjc,11288
195
+ lionagi-0.8.4.dist-info/RECORD,,