lionagi 0.7.7__py3-none-any.whl → 0.8.0__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.
@@ -1,11 +1,8 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
2
- #
3
- # SPDX-License-Identifier: Apache-2.0
1
+ # forms/report.py
4
2
 
5
3
  from pydantic import Field
6
4
 
7
5
  from lionagi.protocols.generic.pile import Pile
8
- from lionagi.utils import UNDEFINED
9
6
 
10
7
  from .base import BaseForm
11
8
  from .form import Form
@@ -13,311 +10,36 @@ from .form import Form
13
10
 
14
11
  class Report(BaseForm):
15
12
  """
16
- Report class that extends BaseForm to manage and track task completion.
17
-
18
- This class provides functionalities to create forms, track completed tasks,
19
- and generate reports based on a template. It is designed to manage
20
- multiple forms and their assignments, keeping track of completed tasks
21
- and their results.
22
-
23
- Attributes:
24
- default_form_template (Type[Form]): Default template for creating forms
25
- strict_form (bool): If True, form cannot be modified after init.
26
- completed_tasks (Pile[Form]): A pile of completed tasks.
27
- completed_task_assignments (dict[str, str]): Assignments completed for
28
- the report, mapping form IDs to assignments.
13
+ A minimal class that collects multiple completed forms as "sub-tasks."
14
+ If you have a single FlowDefinition that describes the entire multi-step pipeline,
15
+ you can track each step as a separate form in here.
29
16
  """
30
17
 
31
- default_form_template: type[Form] = Form
32
- strict_form: bool = Field(
33
- default=False,
34
- description="If True, form cannot be modified after init.",
35
- )
36
-
37
- completed_tasks: Pile[Form] = Field(
18
+ default_form_cls: type[Form] = Form
19
+ completed_forms: Pile[Form] = Field(
38
20
  default_factory=lambda: Pile(item_type={Form}),
39
- description="A pile of tasks completed",
21
+ description="A list of forms that have been completed for this report.",
40
22
  )
41
-
42
- completed_task_assignments: dict[str, str] = Field(
23
+ form_assignments: dict[str, str] = Field(
43
24
  default_factory=dict,
44
- description="assignments completed for the report",
25
+ description="Mapping from form ID -> assignment string",
45
26
  )
46
27
 
47
- @property
48
- def work_fields(self) -> list[str]:
49
- """
50
- Get a list of work fields in the report.
51
-
52
- Work fields are fields that are not part of the base report structure
53
- but are added dynamically. These fields represent the core tasks
54
- or assignments being tracked in the report.
55
-
56
- Returns:
57
- list[str]: A list of work fields.
58
- """
59
- base_report_fields = self.__class__.model_fields.keys()
60
- all_fields = self.all_fields.keys()
61
- return [i for i in all_fields if i not in base_report_fields]
62
-
63
- def get_incomplete_fields(
64
- self,
65
- none_as_valid_value: bool = False,
66
- ) -> list[str]:
67
- """
68
- Get a list of incomplete fields in the report.
69
-
70
- This method checks all fields in the report and returns a list of those
71
- that are incomplete, based on whether `None` is considered a valid
72
- value.
73
-
74
- Args:
75
- none_as_valid_value (bool): If True, `None` is considered valid.
76
-
77
- Returns:
78
- list[str]: A list of incomplete fields.
79
- """
80
- base_report_fields = self.__class__.model_fields.keys()
81
-
82
- result = []
83
- for i in self.all_fields:
84
- if i in base_report_fields:
85
- continue
86
- if none_as_valid_value:
87
- if getattr(self, i) is UNDEFINED:
88
- result.append(i)
89
- else:
90
- if getattr(self, i) in [None, UNDEFINED]:
91
- result.append(i)
92
- return result
93
-
94
- def parse_assignment(
95
- self,
96
- input_fields: list[str],
97
- request_fields: list[str],
98
- ) -> str:
99
- """
100
- Parse and create an assignment string from input and request fields.
101
-
102
- This method generates an assignment string in the format
103
- "input_field1, input_field2 -> request_field1, request_field2".
104
-
105
- Args:
106
- input_fields (list[str]): A list of input fields.
107
- request_fields (list[str]): A list of request fields.
108
-
109
- Returns:
110
- str: The parsed assignment string.
111
-
112
- Raises:
113
- ValueError: If input_fields or request_fields are not lists or
114
- if any field is missing from the form.
115
- """
116
- if not isinstance(input_fields, list):
117
- raise TypeError("The input_fields must be a list of strings.")
118
-
119
- if not isinstance(request_fields, list):
120
- raise TypeError("The request_fields must be a list of strings.")
121
-
122
- for i in input_fields + request_fields:
123
- if i not in self.all_fields:
124
- raise ValueError(f"Field {i} is missing.")
125
-
126
- input_assignment = ", ".join(input_fields)
127
- output_assignment = ", ".join(request_fields)
128
- return f"{input_assignment} -> {output_assignment}"
129
-
130
- def create_form(
131
- self,
132
- assignment: str,
133
- *,
134
- input_fields: list[str] | None = None,
135
- request_fields: list[str] | None = None,
136
- task_description: str | None = None,
137
- fill_inputs: bool | None = True,
138
- none_as_valid_value: bool | None = False,
139
- strict=None,
140
- ) -> Form:
141
- """
142
- Create a form based on the assignment or input/request fields.
143
-
144
- This method generates a new form either based on a direct assignment
145
- string or by parsing input and request fields to create the assignment.
146
- The form can be configured to pre-fill input fields and handle `None`
147
- values as valid or invalid.
148
-
149
- Args:
150
- assignment (str): The assignment string defining the task.
151
- input_fields (list[str], optional): A list of input fields.
152
- request_fields (list[str], optional): A list of request fields.
153
- task_description (str, optional): A description of the task.
154
- fill_inputs (bool, optional): Whether to pre-fill input fields.
155
- none_as_valid_value (bool, optional): Treat `None` as valid value.
156
- strict (bool, optional): Whether the form should be strict.
157
-
158
- Returns:
159
- Form: The created form.
160
-
161
- Raises:
162
- ValueError: If both assignment and input/request fields are
163
- provided or if neither is provided.
164
- """
165
- if assignment is not None:
166
- if input_fields is not None or request_fields is not None:
167
- raise ValueError(
168
- "Cannot provide input/request fields with assignment.",
169
- )
170
- else:
171
- if input_fields is None or request_fields is None:
172
- raise ValueError(
173
- "Provide input_fields and request_fields lists together."
174
- )
175
-
176
- if not assignment:
177
- assignment = self.parse_assignment(
178
- input_fields=input_fields,
179
- request_fields=request_fields,
180
- )
181
-
182
- f_ = self.default_form_template.from_form(
183
- assignment=assignment,
184
- form=self,
185
- task_description=task_description,
186
- fill_inputs=fill_inputs,
187
- none_as_valid_value=none_as_valid_value,
188
- strict=strict if isinstance(strict, bool) else self.strict_form,
189
- )
190
- return f_
191
-
192
- def save_completed_form(
193
- self,
194
- form: Form,
195
- update_results=False,
196
- ) -> None:
28
+ def add_completed_form(
29
+ self, form: Form, update_report_fields: bool = False
30
+ ):
197
31
  """
198
- Save a completed form to the report.
199
-
200
- This method adds a form to the `completed_tasks` pile, ensuring that
201
- all fields in the form are compatible with the report. Optionally, it
202
- can update the report fields with results from the form.
203
-
204
- Args:
205
- form (Form): The form to be saved.
206
- update_results (bool): Update the report with form results.
207
-
208
- Raises:
209
- ValueError: If the form is incomplete or if its fields do not
210
- match the report's fields.
32
+ Add a completed form. Optionally update the report’s fields from the form's output.
211
33
  """
212
- try:
213
- form.check_is_completed(handle_how="raise")
214
- except Exception as e:
215
- raise ValueError(f"Failed to add completed form. Error: {e}")
216
-
217
- report_fields = self.all_fields.keys()
218
- for i in form.work_dict.keys():
219
- if i not in report_fields:
220
- raise ValueError(
221
- f"The task does not match the report. "
222
- f"Field {i} in task assignment not found in report."
223
- )
224
-
225
- self.completed_tasks.include(form)
226
- self.completed_task_assignments[form.id] = form.assignment
227
-
228
- if update_results:
229
- for i in form.request_fields:
230
- field_result = getattr(form, i)
231
- setattr(self, i, field_result)
232
-
233
- @classmethod
234
- def from_form_template(
235
- cls,
236
- template_class: type[BaseForm],
237
- **input_kwargs,
238
- ) -> "Report":
239
- """
240
- Create a report from a form template.
241
-
242
- This method generates a report object using the fields from a specified
243
- form template. The report is populated with input values provided via
244
- keyword arguments.
245
-
246
- Args:
247
- template_class (Type[BaseForm]): The form template class to use.
248
- **input_kwargs: Values to initialize the report's fields.
249
-
250
- Returns:
251
- Report: The generated report.
252
-
253
- Raises:
254
- ValueError: If template class is not a subclass of `BaseForm`.
255
- """
256
- if not issubclass(template_class, BaseForm):
34
+ missing = form.check_completeness()
35
+ if missing:
257
36
  raise ValueError(
258
- "Invalid form template. Must be a subclass of Form.",
37
+ f"Form {form.id} is incomplete: missing {missing}."
259
38
  )
260
- template_class = template_class or cls.default_form_template
261
- rep_template = "report_for_"
262
- rep_template += template_class.model_fields["template_name"].default
263
-
264
- report_obj = cls(template_name=rep_template)
265
-
266
- base_report_fields = cls.model_fields.keys()
267
-
268
- for field, field_info in template_class.model_fields.items():
269
- if field in base_report_fields:
270
- continue
271
- if field not in report_obj.all_fields:
272
- report_obj.add_field(field, field_obj=field_info)
273
- if field in input_kwargs:
274
- value = input_kwargs.get(field)
275
- setattr(report_obj, field, value)
276
-
277
- return report_obj
278
-
279
- @classmethod
280
- def from_form(
281
- cls,
282
- form: BaseForm,
283
- fill_inputs: bool = True,
284
- ) -> "Report":
285
- """
286
- Create a report from an existing form.
287
-
288
- This method generates a report object using the fields from an existing
289
- form, optionally filling the report with the form's input values.
290
-
291
- Args:
292
- form (BaseForm): The form to use as a template.
293
- fill_inputs (bool): Fill the report with form's input values.
294
-
295
- Returns:
296
- Report: The generated report.
297
-
298
- Raises:
299
- ValueError: If form is not an instance of `BaseForm`.
300
- """
301
- if not isinstance(form, BaseForm):
302
- raise TypeError("Invalid form. Should be an instance of BaseForm.")
303
-
304
- report_template_name = "report_for_" + form.template_name
305
- report_obj = cls(template_name=report_template_name)
306
-
307
- base_report_fields = cls.model_fields.keys()
308
-
309
- for field, field_info in form.all_fields.items():
310
- if field in base_report_fields:
311
- continue
312
- if field not in report_obj.all_fields:
313
- report_obj.add_field(field, field_obj=field_info)
314
- if fill_inputs:
315
- value = getattr(form, field)
316
- setattr(report_obj, field, value)
317
-
318
- return report_obj
319
-
320
-
321
- __all__ = ["Report"]
322
-
323
- # File: lion_core/form/report.py
39
+ self.completed_forms.append(form)
40
+ self.form_assignments[form.id] = form.assignment or ""
41
+ # optionally update the report’s own fields
42
+ if update_report_fields:
43
+ for f_ in form.output_fields:
44
+ val = getattr(form, f_, None)
45
+ setattr(self, f_, val)
@@ -10,6 +10,7 @@ from .action.request_response_model import (
10
10
  )
11
11
  from .action.tool import FuncTool, FuncToolRef, Tool, ToolRef
12
12
  from .forms.base import BaseForm
13
+ from .forms.flow import FlowDefinition, FlowStep
13
14
  from .forms.form import Form
14
15
  from .forms.report import Report
15
16
  from .instruct.base import (
@@ -66,4 +67,6 @@ __all__ = (
66
67
  "FuncTool",
67
68
  "FuncToolRef",
68
69
  "FunctionCalling",
70
+ "FlowDefinition",
71
+ "FlowStep",
69
72
  )
lionagi/utils.py CHANGED
@@ -2357,7 +2357,10 @@ def breakdown_pydantic_annotation(
2357
2357
 
2358
2358
 
2359
2359
  def _is_pydantic_model(x: Any) -> bool:
2360
- return isclass(x) and issubclass(x, BaseModel)
2360
+ try:
2361
+ return isclass(x) and issubclass(x, BaseModel)
2362
+ except TypeError:
2363
+ return False
2361
2364
 
2362
2365
 
2363
2366
  def run_package_manager_command(
lionagi/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.7.7"
1
+ __version__ = "0.8.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lionagi
3
- Version: 0.7.7
3
+ Version: 0.8.0
4
4
  Summary: An Intelligence Operating System.
5
5
  Author-email: HaiyangLi <quantocean.li@gmail.com>
6
6
  License: Apache License
@@ -3,8 +3,8 @@ lionagi/_class_registry.py,sha256=dutMsw-FQNqVV5gGH-NEIv90uBkSr8fERJ_x3swbb-s,31
3
3
  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
- lionagi/utils.py,sha256=X12H-O8Lx9tUOKGtjpoxHjRsKYHRqty0qD9i2W12kpI,73121
7
- lionagi/version.py,sha256=eOm8myGPtPLNpkuxL0xhVmstPQbwXv3Ok7FbH0re-TA,22
6
+ lionagi/utils.py,sha256=QbF4E1PG-BaRcEVH3kJIYCJVNq-oRNoTxjda5k8NYW4,73177
7
+ lionagi/version.py,sha256=iPlYCcIzuzW7T2HKDkmYlMkRI51dBLfNRxPPiWrfw9U,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
@@ -45,7 +45,7 @@ lionagi/libs/validate/fuzzy_validate_mapping.py,sha256=SQqyxgrAgJ5zBKxIAnulWsZXb
45
45
  lionagi/libs/validate/string_similarity.py,sha256=7x8D4LZCMNJGz2ZCeKmct7Nc4i8m_ORoHIeGvkeMZOA,8733
46
46
  lionagi/libs/validate/validate_boolean.py,sha256=h3d7Dn7asJokBozWaKxaV_3Y6vUWBc0-zfNJjTQ9Bo8,3614
47
47
  lionagi/operations/__init__.py,sha256=O7nV0tedpUe7_OlUWmCcduGPFtqtzWZcR_SIOnjLsro,134
48
- lionagi/operations/manager.py,sha256=qjDMSOJ35XjDXkVq0SlEb4inTS7OXGwxly2doiQCNas,556
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
51
  lionagi/operations/ReAct/ReAct.py,sha256=tAZ-3Ya68tVUa112wgOMUJpBVw-RWBSYTfgicbInRuQ,3954
@@ -80,7 +80,7 @@ lionagi/operatives/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLa
80
80
  lionagi/operatives/manager.py,sha256=pFGKSOIkXayHfDHCMJJwZXBhx3O02UlYK5mZ_-53AVg,190
81
81
  lionagi/operatives/operative.py,sha256=Pahhjlav-Y1rCYwUZkWNrw6nIOpR9zrqXwuHTYcbjMc,6734
82
82
  lionagi/operatives/step.py,sha256=DevwisZc2q88ynUiiSu7VBEY2A_G4Q5iRLrVgVLHNJU,9843
83
- lionagi/operatives/types.py,sha256=8krpGIeJL2GkO580ePOuAZfGc7vUVPIanemoA77tbVY,1697
83
+ lionagi/operatives/types.py,sha256=X0Pz0aqVg20D3lfnKOZ0GtLj01M5WoYagVmu_aArkoo,1784
84
84
  lionagi/operatives/action/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
85
85
  lionagi/operatives/action/function_calling.py,sha256=dHWxnWj-YD2PkYoRO_iOI1dryb8tThuPDX1OMI0y8GM,4631
86
86
  lionagi/operatives/action/manager.py,sha256=FXfWhQMSFE5qJNZPpgdz4ePvthLafZfnmak2PImCrsc,8824
@@ -88,10 +88,10 @@ lionagi/operatives/action/request_response_model.py,sha256=mCyKub_WoEttJ_mqLhGoO
88
88
  lionagi/operatives/action/tool.py,sha256=CVCNd154XDxRvinmfO_2y72RsCn3UfZEecY7QG2qIjE,5217
89
89
  lionagi/operatives/action/utils.py,sha256=vUe7Aysuzbg16rAfe2Ttp5QUz5_L6mMedBVAWzGAHwk,4330
90
90
  lionagi/operatives/forms/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
91
- lionagi/operatives/forms/base.py,sha256=ALPREgOkRcY2wtRG0JpTXztlohkRjyCiwoleQfGCpSg,7207
92
- lionagi/operatives/forms/form.py,sha256=5z5VfDqcKVFYvhDVZZQwMDczSof2lSx_VxQo32jlkGk,27178
93
- lionagi/operatives/forms/report.py,sha256=KUapeSAB67ElyU1fl4DxtfvobKGnpDPetso6cT6GT4E,11167
94
- lionagi/operatives/forms/utils.py,sha256=sCjYRy-EJIh1py9qIb04LVgALy2YiPHbhXhNyDNwvoQ,701
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
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
97
97
  lionagi/operatives/instruct/instruct.py,sha256=vzIQks5gSXJQzdEE_l4PgJPw2ZUZPbAfZ-cDt6CPmeQ,4794
@@ -189,7 +189,7 @@ lionagi/service/providers/perplexity_/chat_completions.py,sha256=SsDbrtXwQsR4Yu2
189
189
  lionagi/session/__init__.py,sha256=v8vNyJVIVj8_Oz9RJdVe6ZKUQMYTgDh1VQpnr1KdLaw,112
190
190
  lionagi/session/branch.py,sha256=JvErd9YUuGdWyLj37rtKOteSqV0ltn9lg0R2G8GO40c,62539
191
191
  lionagi/session/session.py,sha256=po6C7PnM0iu_ISHUo4PBzzQ61HFOgcsAUfPoO--eLak,8987
192
- lionagi-0.7.7.dist-info/METADATA,sha256=XzhIG5ZehXeF7UXYkd4dvIuqT1W8E969aAOliftxmJU,22819
193
- lionagi-0.7.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
194
- lionagi-0.7.7.dist-info/licenses/LICENSE,sha256=VXFWsdoN5AAknBCgFqQNgPWYx7OPp-PFEP961zGdOjc,11288
195
- lionagi-0.7.7.dist-info/RECORD,,
192
+ lionagi-0.8.0.dist-info/METADATA,sha256=h38ifIVBrti2rDeeyvJiKB991VxdESlYSiIXl7KJsT8,22819
193
+ lionagi-0.8.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
194
+ lionagi-0.8.0.dist-info/licenses/LICENSE,sha256=VXFWsdoN5AAknBCgFqQNgPWYx7OPp-PFEP961zGdOjc,11288
195
+ lionagi-0.8.0.dist-info/RECORD,,
@@ -1,26 +0,0 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
2
- #
3
- # SPDX-License-Identifier: Apache-2.0
4
-
5
- RESTRICTED_FIELDS = {
6
- "input_fields",
7
- "request_fields",
8
- "init_input_kwargs",
9
- "output_fields",
10
- }
11
-
12
-
13
- def get_input_output_fields(str_: str) -> tuple[list[str], list[str]]:
14
- if str_ is None:
15
- return [], []
16
-
17
- if "->" not in str_:
18
- raise ValueError(
19
- "Invalid assignment format. Expected 'inputs -> outputs'.",
20
- )
21
-
22
- inputs, outputs = str_.split("->")
23
- input_fields = [str(i).strip().lower() for i in inputs.split(",")]
24
- request_fields = [str(o).strip().lower() for o in outputs.split(",")]
25
-
26
- return input_fields, request_fields