lionagi 0.0.305__py3-none-any.whl → 0.0.307__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. lionagi/__init__.py +2 -5
  2. lionagi/core/__init__.py +7 -4
  3. lionagi/core/agent/__init__.py +3 -0
  4. lionagi/core/agent/base_agent.py +46 -0
  5. lionagi/core/branch/__init__.py +4 -0
  6. lionagi/core/branch/base/__init__.py +0 -0
  7. lionagi/core/branch/base_branch.py +100 -78
  8. lionagi/core/branch/branch.py +22 -34
  9. lionagi/core/branch/branch_flow_mixin.py +3 -7
  10. lionagi/core/branch/executable_branch.py +192 -0
  11. lionagi/core/branch/util.py +77 -162
  12. lionagi/core/direct/__init__.py +13 -0
  13. lionagi/core/direct/parallel_predict.py +127 -0
  14. lionagi/core/direct/parallel_react.py +0 -0
  15. lionagi/core/direct/parallel_score.py +0 -0
  16. lionagi/core/direct/parallel_select.py +0 -0
  17. lionagi/core/direct/parallel_sentiment.py +0 -0
  18. lionagi/core/direct/predict.py +174 -0
  19. lionagi/core/direct/react.py +33 -0
  20. lionagi/core/direct/score.py +163 -0
  21. lionagi/core/direct/select.py +144 -0
  22. lionagi/core/direct/sentiment.py +51 -0
  23. lionagi/core/direct/utils.py +83 -0
  24. lionagi/core/flow/__init__.py +0 -3
  25. lionagi/core/flow/monoflow/{mono_react.py → ReAct.py} +52 -9
  26. lionagi/core/flow/monoflow/__init__.py +9 -0
  27. lionagi/core/flow/monoflow/{mono_chat.py → chat.py} +11 -11
  28. lionagi/core/flow/monoflow/{mono_chat_mixin.py → chat_mixin.py} +33 -27
  29. lionagi/core/flow/monoflow/{mono_followup.py → followup.py} +7 -6
  30. lionagi/core/flow/polyflow/__init__.py +1 -0
  31. lionagi/core/flow/polyflow/{polychat.py → chat.py} +15 -3
  32. lionagi/core/mail/__init__.py +8 -0
  33. lionagi/core/mail/mail_manager.py +88 -40
  34. lionagi/core/mail/schema.py +32 -6
  35. lionagi/core/messages/__init__.py +3 -0
  36. lionagi/core/messages/schema.py +56 -25
  37. lionagi/core/prompt/__init__.py +0 -0
  38. lionagi/core/prompt/prompt_template.py +0 -0
  39. lionagi/core/schema/__init__.py +7 -5
  40. lionagi/core/schema/action_node.py +29 -0
  41. lionagi/core/schema/base_mixin.py +56 -59
  42. lionagi/core/schema/base_node.py +35 -38
  43. lionagi/core/schema/condition.py +24 -0
  44. lionagi/core/schema/data_logger.py +98 -98
  45. lionagi/core/schema/data_node.py +19 -19
  46. lionagi/core/schema/prompt_template.py +0 -0
  47. lionagi/core/schema/structure.py +293 -190
  48. lionagi/core/session/__init__.py +1 -3
  49. lionagi/core/session/session.py +196 -214
  50. lionagi/core/tool/tool_manager.py +95 -103
  51. lionagi/integrations/__init__.py +1 -3
  52. lionagi/integrations/bridge/langchain_/documents.py +17 -18
  53. lionagi/integrations/bridge/langchain_/langchain_bridge.py +14 -14
  54. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +22 -22
  55. lionagi/integrations/bridge/llamaindex_/node_parser.py +12 -12
  56. lionagi/integrations/bridge/llamaindex_/reader.py +11 -11
  57. lionagi/integrations/bridge/llamaindex_/textnode.py +7 -7
  58. lionagi/integrations/config/openrouter_configs.py +0 -1
  59. lionagi/integrations/provider/oai.py +26 -26
  60. lionagi/integrations/provider/services.py +38 -38
  61. lionagi/libs/__init__.py +34 -1
  62. lionagi/libs/ln_api.py +211 -221
  63. lionagi/libs/ln_async.py +53 -60
  64. lionagi/libs/ln_convert.py +118 -120
  65. lionagi/libs/ln_dataframe.py +32 -33
  66. lionagi/libs/ln_func_call.py +334 -342
  67. lionagi/libs/ln_nested.py +99 -107
  68. lionagi/libs/ln_parse.py +175 -158
  69. lionagi/libs/sys_util.py +52 -52
  70. lionagi/tests/test_core/test_base_branch.py +427 -427
  71. lionagi/tests/test_core/test_branch.py +292 -292
  72. lionagi/tests/test_core/test_mail_manager.py +57 -57
  73. lionagi/tests/test_core/test_session.py +254 -266
  74. lionagi/tests/test_core/test_session_base_util.py +299 -300
  75. lionagi/tests/test_core/test_tool_manager.py +70 -74
  76. lionagi/tests/test_libs/test_nested.py +2 -7
  77. lionagi/tests/test_libs/test_parse.py +2 -2
  78. lionagi/version.py +1 -1
  79. {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/METADATA +4 -2
  80. lionagi-0.0.307.dist-info/RECORD +115 -0
  81. lionagi-0.0.305.dist-info/RECORD +0 -94
  82. {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/LICENSE +0 -0
  83. {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/WHEEL +0 -0
  84. {lionagi-0.0.305.dist-info → lionagi-0.0.307.dist-info}/top_level.txt +0 -0
lionagi/libs/ln_nested.py CHANGED
@@ -25,13 +25,13 @@ def nset(nested_structure: dict | list, indices: list[int | str], value: Any) ->
25
25
  incorrect.
26
26
 
27
27
  Examples:
28
- >>> data = {'a': {'b': [10, 20]}}
29
- >>> nset(data, ['a', 'b', 1], 99)
30
- >>> assert data == {'a': {'b': [10, 99]}}
28
+ >>> data = {'a': {'b': [10, 20]}}
29
+ >>> nset(data, ['a', 'b', 1], 99)
30
+ >>> assert data == {'a': {'b': [10, 99]}}
31
31
 
32
- >>> data = [0, [1, 2], 3]
33
- >>> nset(data, [1, 1], 99)
34
- >>> assert data == [0, [1, 99], 3]
32
+ >>> data = [0, [1, 2], 3]
33
+ >>> nset(data, [1, 1], 99)
34
+ >>> assert data == [0, [1, 99], 3]
35
35
  """
36
36
  if not indices:
37
37
  raise ValueError("Indices list is empty, cannot determine target container")
@@ -77,12 +77,12 @@ def nget(
77
77
  and no default value is provided.
78
78
 
79
79
  Examples:
80
- >>> data = {'a': {'b': [10, 20]}}
81
- >>> assert nget(data, ['a', 'b', 1]) == 20
82
- >>> nget(data, ['a', 'b', 2])
83
- Traceback (most recent call last):
84
- ...
85
- LookupError: Target not found and no default value provided.
80
+ >>> data = {'a': {'b': [10, 20]}}
81
+ >>> assert nget(data, ['a', 'b', 1]) == 20
82
+ >>> nget(data, ['a', 'b', 2])
83
+ Traceback (most recent call last):
84
+ ...
85
+ LookupError: Target not found and no default value provided.
86
86
  """
87
87
 
88
88
  try:
@@ -140,20 +140,20 @@ def nmerge(
140
140
  that defines custom sorting logic for the merged list.
141
141
 
142
142
  Returns:
143
- A merged dictionary or list,
144
- depending on the types present in `iterables`.
143
+ A merged dictionary or list,
144
+ depending on the types present in `iterables`.
145
145
 
146
146
  Raises:
147
- TypeError:
148
- If `iterables`
149
- contains objects of incompatible types that cannot be merged.
147
+ TypeError:
148
+ If `iterables`
149
+ contains objects of incompatible types that cannot be merged.
150
150
 
151
151
  examples:
152
- >>> nmerge([{'a': 1}, {'b': 2}], overwrite=True)
153
- {'a': 1, 'b': 2}
152
+ >>> nmerge([{'a': 1}, {'b': 2}], overwrite=True)
153
+ {'a': 1, 'b': 2}
154
154
 
155
- >>> nmerge([[1, 2], [3, 4]], sort_list=True)
156
- [1, 2, 3, 4]
155
+ >>> nmerge([[1, 2], [3, 4]], sort_list=True)
156
+ [1, 2, 3, 4]
157
157
  """
158
158
  if convert.is_homogeneous(nested_structure, dict):
159
159
  return _merge_dicts(
@@ -196,19 +196,19 @@ def flatten(
196
196
  True, only flattens nested dictionaries, leaving lists intact.
197
197
 
198
198
  Returns:
199
- A flattened dictionary, or None if `inplace` is True.
199
+ A flattened dictionary, or None if `inplace` is True.
200
200
 
201
201
  Raises:
202
- ValueError: If `inplace` is True but `nested_structure` is not a dictionary.
202
+ ValueError: If `inplace` is True but `nested_structure` is not a dictionary.
203
203
 
204
204
  examples:
205
- >>> nested_dict = {'a': {'b': {'c': 1}}}
206
- >>> flatten(nested_dict)
207
- {'a_b_c': 1}
205
+ >>> nested_dict = {'a': {'b': {'c': 1}}}
206
+ >>> flatten(nested_dict)
207
+ {'a_b_c': 1}
208
208
 
209
- >>> nested_list = [{'a': 1}, {'b': 2}]
210
- >>> flatten(nested_list)
211
- {'0_a': 1, '1_b': 2}
209
+ >>> nested_list = [{'a': 1}, {'b': 2}]
210
+ >>> flatten(nested_list)
211
+ {'0_a': 1, '1_b': 2}
212
212
  """
213
213
  if inplace:
214
214
  if not isinstance(nested_structure, dict):
@@ -250,22 +250,22 @@ def unflatten(
250
250
  keys and can limit the reconstruction depth.
251
251
 
252
252
  Args:
253
- flat_dict: A flat dictionary with composite keys to unflatten.
254
- sep: The sep used in composite keys, indicating nested levels.
255
- custom_logic: An optional function to process each part of the composite keys.
256
- max_depth: The maximum depth for nesting during reconstruction.
253
+ flat_dict: A flat dictionary with composite keys to unflatten.
254
+ sep: The sep used in composite keys, indicating nested levels.
255
+ custom_logic: An optional function to process each part of the composite keys.
256
+ max_depth: The maximum depth for nesting during reconstruction.
257
257
 
258
258
  Returns:
259
- The reconstructed nested dictionary or list.
259
+ The reconstructed nested dictionary or list.
260
260
 
261
261
  examples:
262
- >>> flat_dict_ = {'a_b_c': 1}
263
- >>> unflatten(flat_dict_)
264
- {'a': {'b': {'c': 1}}}
262
+ >>> flat_dict_ = {'a_b_c': 1}
263
+ >>> unflatten(flat_dict_)
264
+ {'a': {'b': {'c': 1}}}
265
265
 
266
- >>> flat_dict_ = {'0_a': 1, '1_b': 2}
267
- >>> unflatten(flat_dict_)
268
- [{'a': 1}, {'b': 2}]
266
+ >>> flat_dict_ = {'0_a': 1, '1_b': 2}
267
+ >>> unflatten(flat_dict_)
268
+ [{'a': 1}, {'b': 2}]
269
269
  """
270
270
  unflattened = {}
271
271
  for composite_key, value in flat_dict.items():
@@ -285,9 +285,7 @@ def unflatten(
285
285
  ):
286
286
  max_index = max(unflattened.keys(), default=-1)
287
287
  return [unflattened.get(i) for i in range(max_index + 1)]
288
- if not unflattened:
289
- return {}
290
- return unflattened
288
+ return unflattened or {}
291
289
 
292
290
 
293
291
  def nfilter(
@@ -310,13 +308,13 @@ def nfilter(
310
308
  containing only items that meet the condition.
311
309
 
312
310
  Raises:
313
- TypeError: Raised if `collection` is not a dictionary or a list.
311
+ TypeError: Raised if `collection` is not a dictionary or a list.
314
312
 
315
313
  Examples:
316
- >>> nfilter({'a': 1, 'b': 2, 'c': 3}, lambda x: x[1] > 1)
317
- {'b': 2, 'c': 3}
318
- >>> nfilter([1, 2, 3, 4], lambda x: x % 2 == 0)
319
- [2, 4]
314
+ >>> nfilter({'a': 1, 'b': 2, 'c': 3}, lambda x: x[1] > 1)
315
+ {'b': 2, 'c': 3}
316
+ >>> nfilter([1, 2, 3, 4], lambda x: x % 2 == 0)
317
+ [2, 4]
320
318
  """
321
319
  if isinstance(nested_structure, dict):
322
320
  return _filter_dict(nested_structure, condition)
@@ -353,13 +351,13 @@ def ninsert(
353
351
  depth during recursive calls.
354
352
 
355
353
  Examples:
356
- >>> subject_ = {'a': {'b': [1, 2]}}
357
- >>> ninsert(subject_, ['a', 'b', 2], 3)
358
- >>> assert subject_ == {'a': {'b': [1, 2, 3]}}
354
+ >>> subject_ = {'a': {'b': [1, 2]}}
355
+ >>> ninsert(subject_, ['a', 'b', 2], 3)
356
+ >>> assert subject_ == {'a': {'b': [1, 2, 3]}}
359
357
 
360
- >>> subject_ = []
361
- >>> ninsert(subject_, [0, 'a'], 1)
362
- >>> assert subject_ == [{'a': 1}]
358
+ >>> subject_ = []
359
+ >>> ninsert(subject_, [0, 'a'], 1)
360
+ >>> assert subject_ == [{'a': 1}]
363
361
  """
364
362
  indices = convert.to_list(indices)
365
363
  parts_len = len(indices)
@@ -376,12 +374,10 @@ def ninsert(
376
374
  ):
377
375
  next_part = indices[i + 1]
378
376
  nested_structure[part] = [] if isinstance(next_part, int) else {}
379
- nested_structure = nested_structure[part]
380
- else:
381
- if part not in nested_structure:
382
- next_part = indices[i + 1]
383
- nested_structure[part] = [] if isinstance(next_part, int) else {}
384
- nested_structure = nested_structure[part]
377
+ elif part not in nested_structure:
378
+ next_part = indices[i + 1]
379
+ nested_structure[part] = [] if isinstance(next_part, int) else {}
380
+ nested_structure = nested_structure[part]
385
381
  current_depth += 1
386
382
  parts_depth += 1
387
383
 
@@ -391,11 +387,10 @@ def ninsert(
391
387
  last_part = indices[-1]
392
388
  if isinstance(last_part, int):
393
389
  _handle_list_insert(nested_structure, last_part, value)
390
+ elif isinstance(nested_structure, list):
391
+ nested_structure.append({last_part: value})
394
392
  else:
395
- if isinstance(nested_structure, list):
396
- nested_structure.append({last_part: value})
397
- else:
398
- nested_structure[last_part] = value
393
+ nested_structure[last_part] = value
399
394
 
400
395
 
401
396
  # noinspection PyDecorator
@@ -423,32 +418,29 @@ def get_flattened_keys(
423
418
  modifying the original object.
424
419
 
425
420
  Returns:
426
- A list of strings representing the keys in the flattened structure.
421
+ A list of strings representing the keys in the flattened structure.
427
422
 
428
423
  Raises:
429
- ValueError: If `inplace` is True but `nested_structure` is not a dictionary.
424
+ ValueError: If `inplace` is True but `nested_structure` is not a dictionary.
430
425
 
431
426
  Examples:
432
- >>> nested_dict = {'a': 1, 'b': {'c': 2, 'd': {'e': 3}}}
433
- >>> keys = get_flattened_keys(nested_dict)
434
- >>> assert keys == ['a', 'b_c', 'b_d_e']
427
+ >>> nested_dict = {'a': 1, 'b': {'c': 2, 'd': {'e': 3}}}
428
+ >>> keys = get_flattened_keys(nested_dict)
429
+ >>> assert keys == ['a', 'b_c', 'b_d_e']
435
430
 
436
- >>> nested_list = [{'a': 1}, {'b': 2}]
437
- >>> keys = get_flattened_keys(nested_list)
438
- >>> assert keys == ['0_a', '1_b']
431
+ >>> nested_list = [{'a': 1}, {'b': 2}]
432
+ >>> keys = get_flattened_keys(nested_list)
433
+ >>> assert keys == ['0_a', '1_b']
439
434
  """
440
- if inplace:
441
- obj_copy = SysUtil.create_copy(nested_structure, num=1)
442
- flatten(
443
- obj_copy, sep=sep, max_depth=max_depth, inplace=True, dict_only=dict_only
444
- )
445
- return convert.to_list(obj_copy.keys())
446
- else:
435
+ if not inplace:
447
436
  return convert.to_list(
448
437
  flatten(
449
438
  nested_structure, sep=sep, max_depth=max_depth, dict_only=dict_only
450
439
  ).keys()
451
440
  )
441
+ obj_copy = SysUtil.create_copy(nested_structure, num=1)
442
+ flatten(obj_copy, sep=sep, max_depth=max_depth, inplace=True, dict_only=dict_only)
443
+ return convert.to_list(obj_copy.keys())
452
444
 
453
445
 
454
446
  def _dynamic_flatten_in_place(
@@ -469,19 +461,19 @@ def _dynamic_flatten_in_place(
469
461
  dictionaries and to a certain depth.
470
462
 
471
463
  Args:
472
- nested_structure: The structure to flatten.
473
- parent_key: Initial key prefix for all keys in the flattened structure.
474
- sep: Separator for nested keys.
475
- max_depth: Limits the flattening to a specific depth.
476
- current_depth: Tracks the current depth in the recursion.
477
- dict_only: Limits the flattening to dictionaries only, ignoring lists.
464
+ nested_structure: The structure to flatten.
465
+ parent_key: Initial key prefix for all keys in the flattened structure.
466
+ sep: Separator for nested keys.
467
+ max_depth: Limits the flattening to a specific depth.
468
+ current_depth: Tracks the current depth in the recursion.
469
+ dict_only: Limits the flattening to dictionaries only, ignoring lists.
478
470
 
479
471
  Note:
480
- This function modifies `nested_structure` in place.
472
+ This function modifies `nested_structure` in place.
481
473
 
482
474
  Examples:
483
- Given a nested dictionary `nested_dict` with the appropriate structure,
484
- `_dynamic_flatten_in_place(nested_dict)` will modify it to a flattened form.
475
+ Given a nested dictionary `nested_dict` with the appropriate structure,
476
+ `_dynamic_flatten_in_place(nested_dict)` will modify it to a flattened form.
485
477
  """
486
478
  if isinstance(nested_structure, dict):
487
479
  keys_to_delete = []
@@ -525,12 +517,12 @@ def _handle_list_insert(nested_structure: list, part: int, value: Any) -> None:
525
517
  `None` values up to the index, then the specified value is inserted.
526
518
 
527
519
  Args:
528
- nested_structure: The list to modify.
529
- part: The target index for inserting or replacing the value.
530
- value: The value to be inserted or to replace an existing value in the list.
520
+ nested_structure: The list to modify.
521
+ part: The target index for inserting or replacing the value.
522
+ value: The value to be inserted or to replace an existing value in the list.
531
523
 
532
524
  Note:
533
- This function directly modifies the input list in place.
525
+ This function directly modifies the input list in place.
534
526
  """
535
527
  while len(nested_structure) <= part:
536
528
  nested_structure.append(None)
@@ -547,9 +539,9 @@ def _ensure_list_index(lst_: list, index: int, default: Any = None) -> None:
547
539
  with a specified default value until it reaches the required length.
548
540
 
549
541
  Args:
550
- lst_: The list to extend.
551
- index: The target index that the list should reach or exceed.
552
- default: The value to append to the list for extension. Defaults to None.
542
+ lst_: The list to extend.
543
+ index: The target index that the list should reach or exceed.
544
+ default: The value to append to the list for extension. Defaults to None.
553
545
 
554
546
  Note: Modifies the list in place, ensuring it can safely be indexed at `index`
555
547
  without raising an IndexError.
@@ -569,14 +561,14 @@ def _deep_update(original: dict, update: dict) -> dict:
569
561
  the key-value pair to `original`.
570
562
 
571
563
  Args:
572
- original: The dictionary to update.
573
- update: The dictionary containing updates to apply to `original`.
564
+ original: The dictionary to update.
565
+ update: The dictionary containing updates to apply to `original`.
574
566
 
575
567
  Returns:
576
- The `original` dictionary after applying updates from `update`.
568
+ The `original` dictionary after applying updates from `update`.
577
569
 
578
570
  Note:
579
- This method modifies the `original` dictionary in place.
571
+ This method modifies the `original` dictionary in place.
580
572
  """
581
573
  for key, value in update.items():
582
574
  if isinstance(value, dict) and key in original:
@@ -646,14 +638,14 @@ def _deep_merge_dicts(dict1: dict, dict2: dict) -> dict:
646
638
  pairs from `dict2`.
647
639
 
648
640
  Args:
649
- dict1: The target dictionary to update with values from `dict2`.
650
- dict2: The source dictionary providing updates and additional key-value pairs.
641
+ dict1: The target dictionary to update with values from `dict2`.
642
+ dict2: The source dictionary providing updates and additional key-value pairs.
651
643
 
652
644
  Returns:
653
- The updated dictionary `dict1` with deeply merged values from `dict2`.
645
+ The updated dictionary `dict1` with deeply merged values from `dict2`.
654
646
 
655
647
  Note:
656
- Modifies `dict1` in place, reflecting merged changes from `dict2`.
648
+ Modifies `dict1` in place, reflecting merged changes from `dict2`.
657
649
  """
658
650
  for key in dict2:
659
651
  if key in dict1:
@@ -712,9 +704,9 @@ def _merge_sequences(
712
704
  mechanism or a custom sorting function provided by the user.
713
705
 
714
706
  Args:
715
- iterables: A collection of iterable sequences to be merged.
716
- sort_list: Determines whether to sort the merged list.
717
- custom_sort: Optional. A function defining custom sort criteria.
707
+ iterables: A collection of iterable sequences to be merged.
708
+ sort_list: Determines whether to sort the merged list.
709
+ custom_sort: Optional. A function defining custom sort criteria.
718
710
 
719
711
  Returns: list[Any]: The merged (and potentially sorted) list of elements from
720
712
  all provided iterables.
@@ -765,7 +757,7 @@ def _filter_list(lst: list[Any], condition: Callable[[Any], bool]) -> list[Any]:
765
757
  the filtered list.
766
758
 
767
759
  Returns:
768
- list[Any]: A new list comprising elements that meet the condition.
760
+ list[Any]: A new list comprising elements that meet the condition.
769
761
  """
770
762
  return [item for item in lst if condition(item)]
771
763