lionagi 0.8.8__py3-none-any.whl → 0.9.1__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 (164) 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 +214 -21
  40. lionagi/operations/ReAct/__init__.py +1 -1
  41. lionagi/operations/ReAct/utils.py +14 -3
  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 +1 -1
  108. lionagi/protocols/generic/log.py +1 -1
  109. lionagi/protocols/generic/pile.py +1 -1
  110. lionagi/protocols/generic/processor.py +1 -1
  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 +54 -49
  134. lionagi/service/endpoints/chat_completion.py +1 -1
  135. lionagi/service/endpoints/match_endpoint.py +1 -1
  136. lionagi/service/endpoints/rate_limited_processor.py +1 -1
  137. lionagi/service/endpoints/token_calculator.py +1 -1
  138. lionagi/service/imodel.py +2 -3
  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 +104 -11
  154. lionagi/session/prompts.py +61 -0
  155. lionagi/session/session.py +1 -1
  156. lionagi/settings.py +1 -1
  157. lionagi/tools/file/reader.py +12 -7
  158. lionagi/utils.py +1 -1
  159. lionagi/version.py +1 -1
  160. {lionagi-0.8.8.dist-info → lionagi-0.9.1.dist-info}/METADATA +1 -1
  161. lionagi-0.9.1.dist-info/RECORD +202 -0
  162. lionagi-0.8.8.dist-info/RECORD +0 -201
  163. {lionagi-0.8.8.dist-info → lionagi-0.9.1.dist-info}/WHEEL +0 -0
  164. {lionagi-0.8.8.dist-info → lionagi-0.9.1.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