lionagi 0.8.7__py3-none-any.whl → 0.9.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.
Files changed (166) hide show
  1. lionagi/__init__.py +1 -1
  2. lionagi/_class_registry.py +1 -1
  3. lionagi/_errors.py +1 -1
  4. lionagi/libs/__init__.py +1 -1
  5. lionagi/libs/file/__init__.py +1 -1
  6. lionagi/libs/file/chunk.py +1 -1
  7. lionagi/libs/file/file_ops.py +1 -1
  8. lionagi/libs/file/params.py +1 -1
  9. lionagi/libs/file/process.py +1 -1
  10. lionagi/libs/file/save.py +1 -1
  11. lionagi/libs/nested/__init__.py +1 -1
  12. lionagi/libs/nested/flatten.py +1 -1
  13. lionagi/libs/nested/nfilter.py +1 -1
  14. lionagi/libs/nested/nget.py +1 -1
  15. lionagi/libs/nested/ninsert.py +1 -1
  16. lionagi/libs/nested/nmerge.py +1 -1
  17. lionagi/libs/nested/npop.py +1 -1
  18. lionagi/libs/nested/nset.py +1 -1
  19. lionagi/libs/nested/unflatten.py +1 -1
  20. lionagi/libs/nested/utils.py +1 -1
  21. lionagi/libs/package/__init__.py +1 -1
  22. lionagi/libs/package/imports.py +1 -1
  23. lionagi/libs/package/management.py +1 -1
  24. lionagi/libs/package/params.py +1 -1
  25. lionagi/libs/package/system.py +1 -1
  26. lionagi/libs/parse.py +1 -1
  27. lionagi/libs/schema/__init__.py +1 -1
  28. lionagi/libs/schema/as_readable.py +151 -87
  29. lionagi/libs/schema/extract_code_block.py +1 -1
  30. lionagi/libs/schema/extract_docstring.py +1 -1
  31. lionagi/libs/schema/function_to_schema.py +1 -1
  32. lionagi/libs/schema/json_schema.py +1 -1
  33. lionagi/libs/validate/__init__.py +1 -1
  34. lionagi/libs/validate/common_field_validators.py +1 -1
  35. lionagi/libs/validate/fuzzy_match_keys.py +1 -1
  36. lionagi/libs/validate/fuzzy_validate_mapping.py +1 -1
  37. lionagi/libs/validate/string_similarity.py +1 -1
  38. lionagi/libs/validate/validate_boolean.py +1 -1
  39. lionagi/operations/ReAct/ReAct.py +54 -8
  40. lionagi/operations/ReAct/__init__.py +1 -1
  41. lionagi/operations/ReAct/utils.py +6 -1
  42. lionagi/operations/__init__.py +1 -1
  43. lionagi/operations/_act/__init__.py +1 -1
  44. lionagi/operations/_act/act.py +6 -1
  45. lionagi/operations/brainstorm/__init__.py +1 -1
  46. lionagi/operations/brainstorm/brainstorm.py +1 -1
  47. lionagi/operations/brainstorm/prompt.py +1 -1
  48. lionagi/operations/chat/__init__.py +1 -1
  49. lionagi/operations/chat/chat.py +1 -1
  50. lionagi/operations/communicate/communicate.py +1 -1
  51. lionagi/operations/instruct/__init__.py +1 -1
  52. lionagi/operations/instruct/instruct.py +1 -1
  53. lionagi/operations/interpret/__init__.py +1 -1
  54. lionagi/operations/interpret/interpret.py +9 -38
  55. lionagi/operations/operate/__init__.py +1 -1
  56. lionagi/operations/operate/operate.py +1 -1
  57. lionagi/operations/parse/__init__.py +1 -1
  58. lionagi/operations/parse/parse.py +12 -2
  59. lionagi/operations/plan/__init__.py +1 -1
  60. lionagi/operations/plan/plan.py +1 -1
  61. lionagi/operations/plan/prompt.py +1 -1
  62. lionagi/operations/select/__init__.py +1 -1
  63. lionagi/operations/select/select.py +1 -1
  64. lionagi/operations/select/utils.py +1 -1
  65. lionagi/operations/types.py +1 -1
  66. lionagi/operations/utils.py +1 -1
  67. lionagi/operatives/__init__.py +1 -1
  68. lionagi/operatives/action/__init__.py +1 -1
  69. lionagi/operatives/action/function_calling.py +1 -1
  70. lionagi/operatives/action/manager.py +1 -1
  71. lionagi/operatives/action/request_response_model.py +1 -1
  72. lionagi/operatives/action/tool.py +1 -1
  73. lionagi/operatives/action/utils.py +1 -1
  74. lionagi/operatives/forms/__init__.py +1 -1
  75. lionagi/operatives/instruct/__init__.py +1 -1
  76. lionagi/operatives/instruct/base.py +1 -1
  77. lionagi/operatives/instruct/instruct.py +1 -1
  78. lionagi/operatives/instruct/instruct_collection.py +1 -1
  79. lionagi/operatives/instruct/node.py +1 -1
  80. lionagi/operatives/instruct/prompts.py +1 -1
  81. lionagi/operatives/instruct/reason.py +1 -1
  82. lionagi/operatives/manager.py +1 -1
  83. lionagi/operatives/models/__init__.py +1 -1
  84. lionagi/operatives/models/field_model.py +1 -1
  85. lionagi/operatives/models/model_params.py +1 -1
  86. lionagi/operatives/models/note.py +1 -1
  87. lionagi/operatives/models/operable_model.py +1 -1
  88. lionagi/operatives/models/schema_model.py +1 -1
  89. lionagi/operatives/operative.py +1 -1
  90. lionagi/operatives/step.py +1 -1
  91. lionagi/operatives/strategies/__init__.py +1 -1
  92. lionagi/operatives/strategies/base.py +1 -1
  93. lionagi/operatives/strategies/concurrent.py +1 -1
  94. lionagi/operatives/strategies/concurrent_chunk.py +1 -1
  95. lionagi/operatives/strategies/concurrent_sequential_chunk.py +1 -1
  96. lionagi/operatives/strategies/params.py +1 -1
  97. lionagi/operatives/strategies/sequential.py +1 -1
  98. lionagi/operatives/strategies/sequential_chunk.py +1 -1
  99. lionagi/operatives/strategies/sequential_concurrent_chunk.py +1 -1
  100. lionagi/operatives/strategies/utils.py +1 -1
  101. lionagi/operatives/types.py +1 -1
  102. lionagi/protocols/__init__.py +1 -1
  103. lionagi/protocols/_concepts.py +1 -1
  104. lionagi/protocols/adapters/adapter.py +1 -1
  105. lionagi/protocols/generic/__init__.py +1 -1
  106. lionagi/protocols/generic/element.py +1 -1
  107. lionagi/protocols/generic/event.py +11 -1
  108. lionagi/protocols/generic/log.py +1 -1
  109. lionagi/protocols/generic/pile.py +1 -1
  110. lionagi/protocols/generic/processor.py +11 -3
  111. lionagi/protocols/generic/progression.py +1 -1
  112. lionagi/protocols/graph/__init__.py +1 -1
  113. lionagi/protocols/graph/edge.py +1 -1
  114. lionagi/protocols/graph/graph.py +1 -1
  115. lionagi/protocols/graph/node.py +1 -1
  116. lionagi/protocols/mail/__init__.py +1 -1
  117. lionagi/protocols/mail/exchange.py +1 -1
  118. lionagi/protocols/mail/mail.py +1 -1
  119. lionagi/protocols/mail/mailbox.py +1 -1
  120. lionagi/protocols/mail/manager.py +1 -1
  121. lionagi/protocols/mail/package.py +1 -1
  122. lionagi/protocols/messages/__init__.py +1 -1
  123. lionagi/protocols/messages/action_request.py +1 -1
  124. lionagi/protocols/messages/action_response.py +1 -1
  125. lionagi/protocols/messages/assistant_response.py +1 -1
  126. lionagi/protocols/messages/base.py +1 -1
  127. lionagi/protocols/messages/instruction.py +2 -1
  128. lionagi/protocols/messages/manager.py +1 -1
  129. lionagi/protocols/messages/message.py +1 -1
  130. lionagi/protocols/messages/system.py +1 -1
  131. lionagi/protocols/types.py +1 -1
  132. lionagi/service/endpoints/__init__.py +1 -1
  133. lionagi/service/endpoints/base.py +192 -74
  134. lionagi/service/endpoints/chat_completion.py +11 -5
  135. lionagi/service/endpoints/match_endpoint.py +1 -1
  136. lionagi/service/endpoints/rate_limited_processor.py +18 -7
  137. lionagi/service/endpoints/token_calculator.py +1 -1
  138. lionagi/service/imodel.py +65 -12
  139. lionagi/service/manager.py +1 -1
  140. lionagi/service/providers/__init__.py +1 -1
  141. lionagi/service/providers/anthropic_/__init__.py +1 -1
  142. lionagi/service/providers/anthropic_/messages.py +1 -1
  143. lionagi/service/providers/groq_/__init__.py +1 -1
  144. lionagi/service/providers/groq_/chat_completions.py +1 -1
  145. lionagi/service/providers/openai_/__init__.py +1 -1
  146. lionagi/service/providers/openai_/chat_completions.py +37 -2
  147. lionagi/service/providers/openrouter_/__init__.py +1 -1
  148. lionagi/service/providers/openrouter_/chat_completions.py +1 -1
  149. lionagi/service/providers/perplexity_/__init__.py +1 -1
  150. lionagi/service/providers/perplexity_/chat_completions.py +1 -1
  151. lionagi/service/types.py +1 -1
  152. lionagi/session/__init__.py +1 -1
  153. lionagi/session/branch.py +35 -8
  154. lionagi/session/prompts.py +61 -0
  155. lionagi/session/session.py +1 -1
  156. lionagi/settings.py +1 -1
  157. lionagi/tools/file/__init__.py +0 -0
  158. lionagi/tools/{reader.py → file/reader.py} +13 -8
  159. lionagi/tools/types.py +1 -1
  160. lionagi/utils.py +1 -1
  161. lionagi/version.py +1 -1
  162. {lionagi-0.8.7.dist-info → lionagi-0.9.0.dist-info}/METADATA +6 -3
  163. lionagi-0.9.0.dist-info/RECORD +202 -0
  164. lionagi-0.8.7.dist-info/RECORD +0 -200
  165. {lionagi-0.8.7.dist-info → lionagi-0.9.0.dist-info}/WHEEL +0 -0
  166. {lionagi-0.8.7.dist-info → lionagi-0.9.0.dist-info}/licenses/LICENSE +0 -0
lionagi/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
lionagi/_errors.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
lionagi/libs/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
@@ -1,3 +1,3 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
lionagi/libs/file/save.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,3 +1,3 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,3 +1,3 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
lionagi/libs/parse.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,3 +1,3 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -8,103 +8,167 @@ from typing import Any
8
8
  from lionagi.utils import to_dict
9
9
 
10
10
 
11
- def as_readable_json(input_: Any, /, **kwargs) -> str:
12
- """Convert input to a human-readable JSON string.
13
-
14
- Args:
15
- input_: Object to convert to readable JSON
16
- **kwargs: Additional arguments passed to json.dumps()
17
-
18
- Returns:
19
- A formatted, human-readable JSON string
20
-
21
- Raises:
22
- ValueError: If conversion to JSON fails
11
+ def in_notebook() -> bool:
12
+ """
13
+ Checks if we're running inside a Jupyter notebook.
14
+ Returns True if yes, False otherwise.
23
15
  """
24
- # Extract to_dict kwargs
25
- to_dict_kwargs = {
26
- "use_model_dump": True,
27
- "fuzzy_parse": True,
28
- "recursive": True,
29
- "recursive_python_only": False,
30
- "max_recursive_depth": 5,
31
- }
32
- to_dict_kwargs.update(kwargs)
33
-
34
- # Handle empty input
35
- if not input_:
36
- if isinstance(input_, list):
37
- return ""
38
- return "{}"
39
-
40
16
  try:
41
- if isinstance(input_, list):
42
- # For lists, convert and format each item separately
43
- items = []
44
- for item in input_:
45
- dict_ = to_dict(item, **to_dict_kwargs)
46
- items.append(
47
- json.dumps(
48
- dict_,
49
- indent=2,
50
- ensure_ascii=False,
51
- default=lambda o: to_dict(o),
52
- )
53
- )
54
- return "\n\n".join(items)
55
-
56
- # Handle single items
57
- dict_ = to_dict(input_, **to_dict_kwargs)
58
-
59
- # Extract json.dumps kwargs from input kwargs
60
- json_kwargs = {
61
- "indent": 2,
62
- "ensure_ascii": kwargs.get("ensure_ascii", False),
63
- "default": lambda o: to_dict(o),
64
- }
65
-
66
- # Add any other JSON-specific kwargs
67
- for k in ["indent", "separators", "cls"]:
68
- if k in kwargs:
69
- json_kwargs[k] = kwargs[k]
17
+ from IPython import get_ipython
70
18
 
71
- # Convert to JSON string
72
- if kwargs.get("ensure_ascii", False):
73
- # Force ASCII encoding for special characters
74
- return json.dumps(
75
- dict_,
76
- ensure_ascii=True,
77
- **{
78
- k: v for k, v in json_kwargs.items() if k != "ensure_ascii"
79
- },
80
- )
19
+ shell = get_ipython().__class__.__name__
20
+ return "ZMQInteractiveShell" in shell
21
+ except Exception:
22
+ return False
81
23
 
82
- return json.dumps(dict_, **json_kwargs)
83
24
 
84
- except Exception as e:
85
- raise ValueError(
86
- f"Failed to convert input to readable JSON: {e}"
87
- ) from e
25
+ def format_dict(data: Any, indent: int = 0) -> str:
26
+ """
27
+ Recursively format Python data (dicts, lists, strings, etc.) into a
28
+ YAML-like readable string.
88
29
 
30
+ - Multi-line strings are displayed using a '|' block style, each line indented.
31
+ - Lists are shown with a '- ' prefix per item at the appropriate indentation.
32
+ - Dict keys are shown as "key:" lines, with values on subsequent lines if complex.
33
+ """
34
+ lines = []
35
+ prefix = " " * indent # 2 spaces per indent level
36
+
37
+ if isinstance(data, dict):
38
+ for key, value in data.items():
39
+ if isinstance(value, dict):
40
+ # Nested dict
41
+ lines.append(f"{prefix}{key}:")
42
+ lines.append(format_dict(value, indent + 1))
43
+ elif isinstance(value, list):
44
+ # List under a key
45
+ lines.append(f"{prefix}{key}:")
46
+ for item in value:
47
+ item_str = format_dict(item, indent + 2).lstrip()
48
+ lines.append(f"{prefix} - {item_str}")
49
+ elif isinstance(value, str) and "\n" in value:
50
+ # Multi-line string
51
+ lines.append(f"{prefix}{key}: |")
52
+ subprefix = " " * (indent + 1)
53
+ for line in value.splitlines():
54
+ lines.append(f"{subprefix}{line}")
55
+ else:
56
+ # Simple single-line scalar
57
+ item_str = format_dict(value, indent + 1).lstrip()
58
+ lines.append(f"{prefix}{key}: {item_str}")
59
+ return "\n".join(lines)
60
+
61
+ elif isinstance(data, list):
62
+ # For top-level or nested lists
63
+ for item in data:
64
+ item_str = format_dict(item, indent + 1).lstrip()
65
+ lines.append(f"{prefix}- {item_str}")
66
+ return "\n".join(lines)
67
+
68
+ # Base case: single-line scalar
69
+ return prefix + str(data)
70
+
71
+
72
+ def as_readable(
73
+ input_: Any,
74
+ /,
75
+ *,
76
+ md: bool = False,
77
+ format_curly: bool = False,
78
+ display_str: bool = False,
79
+ max_chars: int | None = None,
80
+ ) -> str:
81
+ """
82
+ Convert `input_` into a human-readable string. If `format_curly=True`, uses
83
+ a YAML-like style (`format_dict`). Otherwise, pretty-printed JSON.
89
84
 
90
- def as_readable(input_: Any, /, *, md: bool = False, **kwargs) -> str:
91
- """Convert input to readable string with optional markdown formatting.
85
+ - For Pydantic models or nested data, uses `to_dict` to get a dictionary.
86
+ - If the result is a list of items, each is processed and concatenated.
92
87
 
93
88
  Args:
94
- input_: Object to convert
95
- md: Whether to wrap in markdown block
96
- **kwargs: Additional arguments for as_readable_json()
89
+ input_: The data to convert (could be a single item or list).
90
+ md: If True, wraps the final output in code fences for Markdown display.
91
+ format_curly: If True, use `format_dict`. Otherwise, produce JSON text.
97
92
 
98
93
  Returns:
99
- Formatted string representation
94
+ A formatted string representation of `input_`.
100
95
  """
101
- try:
102
- result = as_readable_json(input_, **kwargs)
103
- if md:
104
- return f"```json\n{result}\n```"
105
- return result
106
96
 
107
- except Exception:
97
+ # 1) Convert the input to a Python dict/list structure
98
+ # (handles recursion, Pydantic models, etc.)
99
+ def to_dict_safe(obj: Any) -> Any:
100
+ # Attempt to call to_dict with typical recursion flags
101
+ to_dict_kwargs = {
102
+ "use_model_dump": True,
103
+ "fuzzy_parse": True,
104
+ "recursive": True,
105
+ "recursive_python_only": False,
106
+ "max_recursive_depth": 5,
107
+ }
108
+ return to_dict(obj, **to_dict_kwargs)
109
+
110
+ def _inner(i_: Any) -> Any:
111
+ try:
112
+ if isinstance(i_, list):
113
+ # Already a list. Convert each item
114
+ items = [to_dict_safe(x) for x in i_]
115
+ else:
116
+ # Single item
117
+ maybe_list = to_dict_safe(i_)
118
+ # If it's a list, store as items; else just single
119
+ items = (
120
+ maybe_list
121
+ if isinstance(maybe_list, list)
122
+ else [maybe_list]
123
+ )
124
+ except Exception:
125
+ # If conversion fails, fallback to str
126
+ return str(i_)
127
+
128
+ # 2) For each item in `items`, either format with YAML-like or JSON
129
+ rendered = []
130
+ for item in items:
131
+ if format_curly:
132
+ # YAML-like
133
+ rendered.append(format_dict(item))
134
+ else:
135
+ # JSON approach
136
+ try:
137
+ # Provide indentation, ensure ASCII not forced
138
+ rendered.append(
139
+ json.dumps(item, indent=2, ensure_ascii=False)
140
+ )
141
+ except Exception:
142
+ # fallback
143
+ rendered.append(str(item))
144
+
145
+ # 3) Combine
146
+ final_str = "\n\n".join(rendered).strip()
147
+
148
+ # 4) If Markdown requested, wrap with code fences
149
+ # - If we used format_curly, we might do "```yaml" instead. But user specifically asked for JSON code blocks previously
108
150
  if md:
109
- return f"```json\n{str(input_)}\n```"
110
- return str(input_)
151
+ if format_curly:
152
+ return f"```yaml\n{final_str}\n```"
153
+ else:
154
+ return f"```json\n{final_str}\n```"
155
+
156
+ return final_str
157
+
158
+ str_ = _inner(input_).strip()
159
+ if max_chars is not None and len(str_) > max_chars:
160
+ str1 = str_[:max_chars] + "...\n\n[Truncated output]\n\n"
161
+ if str_.endswith("\n```"):
162
+ str1 += "```"
163
+ str_ = str1
164
+ if display_str:
165
+ if md and in_notebook():
166
+ # If in IPython environment, display Markdown
167
+ from IPython.display import Markdown, display
168
+
169
+ display(Markdown(str_))
170
+ else:
171
+ # Otherwise, just print the string
172
+ print(str_)
173
+ else:
174
+ return str_
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,3 +1,3 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
@@ -7,11 +7,12 @@ from typing import TYPE_CHECKING, Any
7
7
 
8
8
  from pydantic import BaseModel
9
9
 
10
+ from lionagi.libs.schema.as_readable import as_readable
10
11
  from lionagi.operatives.types import Instruct
11
12
  from lionagi.service.imodel import iModel
12
13
  from lionagi.utils import copy
13
14
 
14
- from .utils import ReActAnalysis
15
+ from .utils import Analysis, ReActAnalysis
15
16
 
16
17
  if TYPE_CHECKING:
17
18
  from lionagi.session.branch import Branch
@@ -24,6 +25,7 @@ async def ReAct(
24
25
  interpret_domain: str | None = None,
25
26
  interpret_style: str | None = None,
26
27
  interpret_sample: str | None = None,
28
+ interpret_model: str | None = None,
27
29
  interpret_kwargs: dict | None = None,
28
30
  tools: Any = None,
29
31
  tool_schemas: Any = None,
@@ -34,8 +36,10 @@ async def ReAct(
34
36
  return_analysis: bool = False,
35
37
  analysis_model: iModel | None = None,
36
38
  verbose_analysis: bool = False,
39
+ verbose_length: int = None,
37
40
  **kwargs,
38
41
  ):
42
+
39
43
  # If no tools or tool schemas are provided, default to "all tools"
40
44
  if not tools and not tool_schemas:
41
45
  tools = True
@@ -52,10 +56,19 @@ async def ReAct(
52
56
  domain=interpret_domain,
53
57
  style=interpret_style,
54
58
  sample_writing=interpret_sample,
59
+ interpret_model=interpret_model,
55
60
  **(interpret_kwargs or {}),
56
61
  )
57
62
  if verbose_analysis:
58
- print(f"Interpreted instruction: {instruction_str}")
63
+ print("\n### Interpreted instruction:\n")
64
+ as_readable(
65
+ instruction_str,
66
+ md=True,
67
+ format_curly=True,
68
+ display_str=True,
69
+ max_chars=verbose_length,
70
+ )
71
+ print("\n----------------------------\n")
59
72
 
60
73
  # Convert Instruct to dict if necessary
61
74
  instruct_dict = (
@@ -89,9 +102,15 @@ async def ReAct(
89
102
 
90
103
  # If verbose, show round #1 analysis
91
104
  if verbose_analysis:
92
- print(
93
- f"ReAct Round #1 Analysis:\n {analysis.model_dump_json(indent=2)}",
105
+ print("\n### ReAct Round No.1 Analysis:\n")
106
+ as_readable(
107
+ analysis,
108
+ md=True,
109
+ format_curly=True,
110
+ display_str=True,
111
+ max_chars=verbose_length,
94
112
  )
113
+ print("\n----------------------------\n")
95
114
 
96
115
  # Validate and clamp max_extensions if needed
97
116
  if max_extensions and max_extensions > 100:
@@ -138,9 +157,16 @@ async def ReAct(
138
157
 
139
158
  # If verbose, show round analysis
140
159
  if verbose_analysis:
141
- print(
142
- f"ReAct Round #{round_count} Analysis:\n {analysis.model_dump_json(indent=2)}",
160
+ print(f"\n### ReAct Round No.{round_count} Analysis:\n")
161
+ as_readable(
162
+ analysis,
163
+ md=True,
164
+ format_curly=True,
165
+ display_str=True,
166
+ max_chars=verbose_length,
143
167
  )
168
+ print("\n----------------------------\n")
169
+
144
170
  if extensions:
145
171
  extensions -= 1
146
172
 
@@ -148,11 +174,31 @@ async def ReAct(
148
174
  answer_prompt = ReActAnalysis.ANSWER_PROMPT.format(
149
175
  instruction=instruct_dict["instruction"]
150
176
  )
151
- out = await branch.communicate(
177
+ if not response_format:
178
+ response_format = Analysis
179
+
180
+ out = await branch.operate(
152
181
  instruction=answer_prompt,
153
182
  response_format=response_format,
154
183
  **(response_kwargs or {}),
155
184
  )
185
+ if isinstance(out, Analysis):
186
+ out = out.analysis
187
+
188
+ if verbose_analysis:
189
+ print("\n### ReAct Response:\n")
190
+ as_readable(
191
+ analysis,
192
+ md=True,
193
+ format_curly=True,
194
+ display_str=True,
195
+ max_chars=verbose_length,
196
+ )
197
+ print("\n----------------------------\n")
198
+
156
199
  if return_analysis:
157
200
  return out, analyses
158
201
  return out
202
+
203
+
204
+ # TODO: Do partial intermeditate output for longer analysis with form and report
@@ -1,3 +1,3 @@
1
- # Copyright (c) 2023 - 2024, HaiyangLi <quantocean.li at gmail dot com>
1
+ # Copyright (c) 2023 - 2025, HaiyangLi <quantocean.li at gmail dot com>
2
2
  #
3
3
  # SPDX-License-Identifier: Apache-2.0