lionagi 0.1.2__py3-none-any.whl → 0.2.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 (268) hide show
  1. lionagi/__init__.py +60 -5
  2. lionagi/core/__init__.py +0 -25
  3. lionagi/core/_setting/_setting.py +59 -0
  4. lionagi/core/action/__init__.py +14 -0
  5. lionagi/core/action/function_calling.py +136 -0
  6. lionagi/core/action/manual.py +1 -0
  7. lionagi/core/action/node.py +109 -0
  8. lionagi/core/action/tool.py +114 -0
  9. lionagi/core/action/tool_manager.py +356 -0
  10. lionagi/core/agent/base_agent.py +27 -13
  11. lionagi/core/agent/eval/evaluator.py +1 -0
  12. lionagi/core/agent/eval/vote.py +40 -0
  13. lionagi/core/agent/learn/learner.py +59 -0
  14. lionagi/core/agent/plan/unit_template.py +1 -0
  15. lionagi/core/collections/__init__.py +17 -0
  16. lionagi/core/{generic/data_logger.py → collections/_logger.py} +69 -55
  17. lionagi/core/collections/abc/__init__.py +53 -0
  18. lionagi/core/collections/abc/component.py +615 -0
  19. lionagi/core/collections/abc/concepts.py +297 -0
  20. lionagi/core/collections/abc/exceptions.py +150 -0
  21. lionagi/core/collections/abc/util.py +45 -0
  22. lionagi/core/collections/exchange.py +161 -0
  23. lionagi/core/collections/flow.py +426 -0
  24. lionagi/core/collections/model.py +419 -0
  25. lionagi/core/collections/pile.py +913 -0
  26. lionagi/core/collections/progression.py +236 -0
  27. lionagi/core/collections/util.py +64 -0
  28. lionagi/core/director/direct.py +314 -0
  29. lionagi/core/director/director.py +2 -0
  30. lionagi/core/{execute/branch_executor.py → engine/branch_engine.py} +134 -97
  31. lionagi/core/{execute/instruction_map_executor.py → engine/instruction_map_engine.py} +80 -55
  32. lionagi/{experimental/directive/evaluator → core/engine}/script_engine.py +17 -1
  33. lionagi/core/executor/base_executor.py +90 -0
  34. lionagi/core/{execute/structure_executor.py → executor/graph_executor.py} +62 -66
  35. lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
  36. lionagi/core/generic/__init__.py +3 -33
  37. lionagi/core/generic/edge.py +29 -79
  38. lionagi/core/generic/edge_condition.py +16 -0
  39. lionagi/core/generic/graph.py +236 -0
  40. lionagi/core/generic/hyperedge.py +1 -0
  41. lionagi/core/generic/node.py +156 -221
  42. lionagi/core/generic/tree.py +48 -0
  43. lionagi/core/generic/tree_node.py +79 -0
  44. lionagi/core/mail/__init__.py +12 -0
  45. lionagi/core/mail/mail.py +25 -0
  46. lionagi/core/mail/mail_manager.py +139 -58
  47. lionagi/core/mail/package.py +45 -0
  48. lionagi/core/mail/start_mail.py +36 -0
  49. lionagi/core/message/__init__.py +19 -0
  50. lionagi/core/message/action_request.py +133 -0
  51. lionagi/core/message/action_response.py +135 -0
  52. lionagi/core/message/assistant_response.py +95 -0
  53. lionagi/core/message/instruction.py +234 -0
  54. lionagi/core/message/message.py +101 -0
  55. lionagi/core/message/system.py +86 -0
  56. lionagi/core/message/util.py +283 -0
  57. lionagi/core/report/__init__.py +4 -0
  58. lionagi/core/report/base.py +217 -0
  59. lionagi/core/report/form.py +231 -0
  60. lionagi/core/report/report.py +166 -0
  61. lionagi/core/report/util.py +28 -0
  62. lionagi/core/rule/_default.py +16 -0
  63. lionagi/core/rule/action.py +99 -0
  64. lionagi/core/rule/base.py +238 -0
  65. lionagi/core/rule/boolean.py +56 -0
  66. lionagi/core/rule/choice.py +47 -0
  67. lionagi/core/rule/mapping.py +96 -0
  68. lionagi/core/rule/number.py +71 -0
  69. lionagi/core/rule/rulebook.py +109 -0
  70. lionagi/core/rule/string.py +52 -0
  71. lionagi/core/rule/util.py +35 -0
  72. lionagi/core/session/branch.py +431 -0
  73. lionagi/core/session/directive_mixin.py +287 -0
  74. lionagi/core/session/session.py +229 -903
  75. lionagi/core/structure/__init__.py +1 -0
  76. lionagi/core/structure/chain.py +1 -0
  77. lionagi/core/structure/forest.py +1 -0
  78. lionagi/core/structure/graph.py +1 -0
  79. lionagi/core/structure/tree.py +1 -0
  80. lionagi/core/unit/__init__.py +5 -0
  81. lionagi/core/unit/parallel_unit.py +245 -0
  82. lionagi/core/unit/template/action.py +81 -0
  83. lionagi/core/unit/template/base.py +51 -0
  84. lionagi/core/unit/template/plan.py +84 -0
  85. lionagi/core/unit/template/predict.py +109 -0
  86. lionagi/core/unit/template/score.py +124 -0
  87. lionagi/core/unit/template/select.py +104 -0
  88. lionagi/core/unit/unit.py +362 -0
  89. lionagi/core/unit/unit_form.py +305 -0
  90. lionagi/core/unit/unit_mixin.py +1168 -0
  91. lionagi/core/unit/util.py +71 -0
  92. lionagi/core/validator/validator.py +364 -0
  93. lionagi/core/work/work.py +74 -0
  94. lionagi/core/work/work_function.py +92 -0
  95. lionagi/core/work/work_queue.py +81 -0
  96. lionagi/core/work/worker.py +195 -0
  97. lionagi/core/work/worklog.py +124 -0
  98. lionagi/experimental/compressor/base.py +46 -0
  99. lionagi/experimental/compressor/llm_compressor.py +247 -0
  100. lionagi/experimental/compressor/llm_summarizer.py +61 -0
  101. lionagi/experimental/compressor/util.py +70 -0
  102. lionagi/experimental/directive/__init__.py +19 -0
  103. lionagi/experimental/directive/parser/base_parser.py +69 -2
  104. lionagi/experimental/directive/{template_ → template}/base_template.py +17 -1
  105. lionagi/{libs/ln_tokenizer.py → experimental/directive/tokenizer.py} +16 -0
  106. lionagi/experimental/{directive/evaluator → evaluator}/ast_evaluator.py +16 -0
  107. lionagi/experimental/{directive/evaluator → evaluator}/base_evaluator.py +16 -0
  108. lionagi/experimental/knowledge/base.py +10 -0
  109. lionagi/experimental/memory/__init__.py +0 -0
  110. lionagi/experimental/strategies/__init__.py +0 -0
  111. lionagi/experimental/strategies/base.py +1 -0
  112. lionagi/integrations/bridge/langchain_/documents.py +4 -0
  113. lionagi/integrations/bridge/llamaindex_/index.py +30 -0
  114. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
  115. lionagi/integrations/chunker/chunk.py +161 -24
  116. lionagi/integrations/config/oai_configs.py +34 -3
  117. lionagi/integrations/config/openrouter_configs.py +14 -2
  118. lionagi/integrations/loader/load.py +122 -21
  119. lionagi/integrations/loader/load_util.py +6 -77
  120. lionagi/integrations/provider/_mapping.py +46 -0
  121. lionagi/integrations/provider/litellm.py +2 -1
  122. lionagi/integrations/provider/mlx_service.py +16 -9
  123. lionagi/integrations/provider/oai.py +91 -4
  124. lionagi/integrations/provider/ollama.py +6 -5
  125. lionagi/integrations/provider/openrouter.py +115 -8
  126. lionagi/integrations/provider/services.py +2 -2
  127. lionagi/integrations/provider/transformers.py +18 -22
  128. lionagi/integrations/storage/__init__.py +3 -3
  129. lionagi/integrations/storage/neo4j.py +52 -60
  130. lionagi/integrations/storage/storage_util.py +44 -46
  131. lionagi/integrations/storage/structure_excel.py +43 -26
  132. lionagi/integrations/storage/to_excel.py +11 -4
  133. lionagi/libs/__init__.py +22 -1
  134. lionagi/libs/ln_api.py +75 -20
  135. lionagi/libs/ln_context.py +37 -0
  136. lionagi/libs/ln_convert.py +21 -9
  137. lionagi/libs/ln_func_call.py +69 -28
  138. lionagi/libs/ln_image.py +107 -0
  139. lionagi/libs/ln_nested.py +26 -11
  140. lionagi/libs/ln_parse.py +82 -23
  141. lionagi/libs/ln_queue.py +16 -0
  142. lionagi/libs/ln_tokenize.py +164 -0
  143. lionagi/libs/ln_validate.py +16 -0
  144. lionagi/libs/special_tokens.py +172 -0
  145. lionagi/libs/sys_util.py +95 -24
  146. lionagi/lions/coder/code_form.py +13 -0
  147. lionagi/lions/coder/coder.py +50 -3
  148. lionagi/lions/coder/util.py +30 -25
  149. lionagi/tests/libs/test_func_call.py +23 -21
  150. lionagi/tests/libs/test_nested.py +36 -21
  151. lionagi/tests/libs/test_parse.py +1 -1
  152. lionagi/tests/test_core/collections/__init__.py +0 -0
  153. lionagi/tests/test_core/collections/test_component.py +206 -0
  154. lionagi/tests/test_core/collections/test_exchange.py +138 -0
  155. lionagi/tests/test_core/collections/test_flow.py +145 -0
  156. lionagi/tests/test_core/collections/test_pile.py +171 -0
  157. lionagi/tests/test_core/collections/test_progression.py +129 -0
  158. lionagi/tests/test_core/generic/test_edge.py +67 -0
  159. lionagi/tests/test_core/generic/test_graph.py +96 -0
  160. lionagi/tests/test_core/generic/test_node.py +106 -0
  161. lionagi/tests/test_core/generic/test_tree_node.py +73 -0
  162. lionagi/tests/test_core/test_branch.py +115 -294
  163. lionagi/tests/test_core/test_form.py +46 -0
  164. lionagi/tests/test_core/test_report.py +105 -0
  165. lionagi/tests/test_core/test_validator.py +111 -0
  166. lionagi/version.py +1 -1
  167. lionagi-0.2.0.dist-info/LICENSE +202 -0
  168. lionagi-0.2.0.dist-info/METADATA +272 -0
  169. lionagi-0.2.0.dist-info/RECORD +240 -0
  170. lionagi/core/branch/base.py +0 -653
  171. lionagi/core/branch/branch.py +0 -474
  172. lionagi/core/branch/flow_mixin.py +0 -96
  173. lionagi/core/branch/util.py +0 -323
  174. lionagi/core/direct/__init__.py +0 -19
  175. lionagi/core/direct/cot.py +0 -123
  176. lionagi/core/direct/plan.py +0 -164
  177. lionagi/core/direct/predict.py +0 -166
  178. lionagi/core/direct/react.py +0 -171
  179. lionagi/core/direct/score.py +0 -279
  180. lionagi/core/direct/select.py +0 -170
  181. lionagi/core/direct/sentiment.py +0 -1
  182. lionagi/core/direct/utils.py +0 -110
  183. lionagi/core/direct/vote.py +0 -64
  184. lionagi/core/execute/base_executor.py +0 -47
  185. lionagi/core/flow/baseflow.py +0 -23
  186. lionagi/core/flow/monoflow/ReAct.py +0 -240
  187. lionagi/core/flow/monoflow/__init__.py +0 -9
  188. lionagi/core/flow/monoflow/chat.py +0 -95
  189. lionagi/core/flow/monoflow/chat_mixin.py +0 -253
  190. lionagi/core/flow/monoflow/followup.py +0 -215
  191. lionagi/core/flow/polyflow/__init__.py +0 -1
  192. lionagi/core/flow/polyflow/chat.py +0 -251
  193. lionagi/core/form/action_form.py +0 -26
  194. lionagi/core/form/field_validator.py +0 -287
  195. lionagi/core/form/form.py +0 -302
  196. lionagi/core/form/mixin.py +0 -214
  197. lionagi/core/form/scored_form.py +0 -13
  198. lionagi/core/generic/action.py +0 -26
  199. lionagi/core/generic/component.py +0 -532
  200. lionagi/core/generic/condition.py +0 -46
  201. lionagi/core/generic/mail.py +0 -90
  202. lionagi/core/generic/mailbox.py +0 -36
  203. lionagi/core/generic/relation.py +0 -70
  204. lionagi/core/generic/signal.py +0 -22
  205. lionagi/core/generic/structure.py +0 -362
  206. lionagi/core/generic/transfer.py +0 -20
  207. lionagi/core/generic/work.py +0 -40
  208. lionagi/core/graph/graph.py +0 -126
  209. lionagi/core/graph/tree.py +0 -190
  210. lionagi/core/mail/schema.py +0 -63
  211. lionagi/core/messages/schema.py +0 -325
  212. lionagi/core/tool/__init__.py +0 -5
  213. lionagi/core/tool/tool.py +0 -28
  214. lionagi/core/tool/tool_manager.py +0 -283
  215. lionagi/experimental/report/form.py +0 -64
  216. lionagi/experimental/report/report.py +0 -138
  217. lionagi/experimental/report/util.py +0 -47
  218. lionagi/experimental/tool/function_calling.py +0 -43
  219. lionagi/experimental/tool/manual.py +0 -66
  220. lionagi/experimental/tool/schema.py +0 -59
  221. lionagi/experimental/tool/tool_manager.py +0 -138
  222. lionagi/experimental/tool/util.py +0 -16
  223. lionagi/experimental/validator/rule.py +0 -139
  224. lionagi/experimental/validator/validator.py +0 -56
  225. lionagi/experimental/work/__init__.py +0 -10
  226. lionagi/experimental/work/async_queue.py +0 -54
  227. lionagi/experimental/work/schema.py +0 -73
  228. lionagi/experimental/work/work_function.py +0 -67
  229. lionagi/experimental/work/worker.py +0 -56
  230. lionagi/experimental/work2/form.py +0 -371
  231. lionagi/experimental/work2/report.py +0 -289
  232. lionagi/experimental/work2/schema.py +0 -30
  233. lionagi/experimental/work2/tests.py +0 -72
  234. lionagi/experimental/work2/work_function.py +0 -89
  235. lionagi/experimental/work2/worker.py +0 -12
  236. lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
  237. lionagi/tests/test_core/generic/test_component.py +0 -89
  238. lionagi/tests/test_core/test_base_branch.py +0 -426
  239. lionagi/tests/test_core/test_chat_flow.py +0 -63
  240. lionagi/tests/test_core/test_mail_manager.py +0 -75
  241. lionagi/tests/test_core/test_prompts.py +0 -51
  242. lionagi/tests/test_core/test_session.py +0 -254
  243. lionagi/tests/test_core/test_session_base_util.py +0 -313
  244. lionagi/tests/test_core/test_tool_manager.py +0 -95
  245. lionagi-0.1.2.dist-info/LICENSE +0 -9
  246. lionagi-0.1.2.dist-info/METADATA +0 -174
  247. lionagi-0.1.2.dist-info/RECORD +0 -206
  248. /lionagi/core/{branch → _setting}/__init__.py +0 -0
  249. /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
  250. /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
  251. /lionagi/core/{form → agent/plan}/__init__.py +0 -0
  252. /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
  253. /lionagi/core/{graph → director}/__init__.py +0 -0
  254. /lionagi/core/{messages → engine}/__init__.py +0 -0
  255. /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
  256. /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
  257. /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
  258. /lionagi/{experimental/report → core/unit/template}/__init__.py +0 -0
  259. /lionagi/{experimental/tool → core/validator}/__init__.py +0 -0
  260. /lionagi/{experimental/validator → core/work}/__init__.py +0 -0
  261. /lionagi/experimental/{work2 → compressor}/__init__.py +0 -0
  262. /lionagi/{core/flow/mono_chat_mixin.py → experimental/directive/template/__init__.py} +0 -0
  263. /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
  264. /lionagi/experimental/{work2/util.py → evaluator/__init__.py} +0 -0
  265. /lionagi/experimental/{work2/work.py → knowledge/__init__.py} +0 -0
  266. /lionagi/{tests/libs/test_async.py → experimental/knowledge/graph.py} +0 -0
  267. {lionagi-0.1.2.dist-info → lionagi-0.2.0.dist-info}/WHEEL +0 -0
  268. {lionagi-0.1.2.dist-info → lionagi-0.2.0.dist-info}/top_level.txt +0 -0
@@ -1,283 +0,0 @@
1
- import asyncio
2
-
3
- from typing import Tuple, Any, TypeVar, Callable
4
- from lionagi.libs import func_call, convert, ParseUtil
5
-
6
- from lionagi.core.tool.tool import Tool, TOOL_TYPE
7
-
8
- T = TypeVar("T", bound=Tool)
9
-
10
-
11
- class ToolManager:
12
- """
13
- A manager class for handling the registration and invocation of tools that are subclasses of Tool.
14
-
15
- This class maintains a registry of tool instances, allowing for dynamic invocation based on
16
- tool name and provided arguments. It supports both synchronous and asynchronous tool function
17
- calls.
18
-
19
- Attributes:
20
- registry (dict[str, Tool]): A dictionary to hold registered tools, keyed by their names.
21
- """
22
-
23
- registry: dict = {}
24
-
25
- def name_existed(self, name: str) -> bool:
26
- """
27
- Checks if a tool name already exists in the registry.
28
-
29
- Args:
30
- name (str): The name of the tool to check.
31
-
32
- Returns:
33
- bool: True if the name exists, False otherwise.
34
- """
35
- return name in self.registry
36
-
37
- @property
38
- def has_tools(self):
39
- return self.registry != {}
40
-
41
- def _register_tool(self, tool: Tool | Callable) -> None:
42
- """
43
- Registers a tool in the registry. Raises a TypeError if the object is not an instance of Tool.
44
-
45
- Args:
46
- tool (Tool): The tool instance to register.
47
-
48
- Raises:
49
- TypeError: If the provided object is not an instance of Tool.
50
- """
51
- if isinstance(tool, Callable):
52
- tool = func_to_tool(tool)[0]
53
- if not isinstance(tool, Tool):
54
- raise TypeError("Please register a Tool object.")
55
- name = tool.schema_["function"]["name"]
56
- self.registry.update({name: tool})
57
-
58
- async def invoke(self, func_calls: Tuple[str, dict[str, Any]]) -> Any:
59
- """
60
- Invokes a registered tool's function with the given arguments. Supports both coroutine and regular functions.
61
-
62
- Args:
63
- func_call (Tuple[str, Dict[str, Any]]): A tuple containing the function name and a dictionary of keyword arguments.
64
-
65
- Returns:
66
- Any: The result of the function call.
67
-
68
- Raises:
69
- ValueError: If the function name is not registered or if there's an error during function invocation.
70
- """
71
- name, kwargs = func_calls
72
- if not self.name_existed(name):
73
- raise ValueError(f"Function {name} is not registered.")
74
- tool = self.registry[name]
75
- func = tool.func
76
- parser = tool.parser
77
- try:
78
- if func_call.is_coroutine_func(func):
79
- tasks = [func_call.call_handler(func, **kwargs)]
80
- out = await asyncio.gather(*tasks)
81
- return parser(out[0]) if parser else out[0]
82
- else:
83
- out = func(**kwargs)
84
- return parser(out) if parser else out
85
- except Exception as e:
86
- raise ValueError(
87
- f"Error when invoking function {name} with arguments {kwargs} with error message {e}"
88
- ) from e
89
-
90
- @staticmethod
91
- def get_function_call(response: dict) -> Tuple[str, dict]:
92
- """
93
- Extracts a function call and arguments from a response dictionary.
94
-
95
- Args:
96
- response (dict): The response dictionary containing the function call information.
97
-
98
- Returns:
99
- Tuple[str, dict]: A tuple containing the function name and a dictionary of arguments.
100
-
101
- Raises:
102
- ValueError: If the response does not contain valid function call information.
103
- """
104
- try:
105
- func = response["action"][7:]
106
- args = convert.to_dict(response["arguments"])
107
- return func, args
108
- except Exception:
109
- try:
110
- func = response["recipient_name"].split(".")[-1]
111
- args = response["parameters"]
112
- return func, args
113
- except:
114
- raise ValueError("response is not a valid function call")
115
-
116
- def register_tools(self, tools: list[Tool]) -> None:
117
- """
118
- Registers multiple tools in the registry.
119
-
120
- Args:
121
- tools (list[Tool]): A list of tool instances to register.
122
- """
123
- func_call.lcall(tools, self._register_tool)
124
-
125
- def to_tool_schema_list(self) -> list[dict[str, Any]]:
126
- """
127
- Generates a list of schemas for all registered tools.
128
-
129
- Returns:
130
- list[dict[str, Any]]: A list of tool schemas.
131
-
132
- """
133
- return [tool.schema_ for tool in self.registry.values()]
134
-
135
- def parse_tool(self, tools: TOOL_TYPE, **kwargs) -> dict:
136
- """
137
- Parses tool information and generates a dictionary for tool invocation.
138
-
139
- Args:
140
- tools: Tool information which can be a single Tool instance, a list of Tool instances, a tool name, or a list of tool names.
141
- **kwargs: Additional keyword arguments.
142
-
143
- Returns:
144
- dict: A dictionary containing tool schema information and any additional keyword arguments.
145
-
146
- Raises:
147
- ValueError: If a tool name is provided that is not registered.
148
- """
149
-
150
- def tool_check(tool):
151
- if isinstance(tool, dict):
152
- return tool
153
- elif isinstance(tool, Tool):
154
- return tool.schema_
155
- elif isinstance(tool, str):
156
- if self.name_existed(tool):
157
- tool: Tool = self.registry[tool]
158
- return tool.schema_
159
- else:
160
- raise ValueError(f"Function {tool} is not registered.")
161
-
162
- if tools:
163
- if isinstance(tools, bool):
164
- tool_kwarg = {"tools": self.to_tool_schema_list()}
165
- kwargs = tool_kwarg | kwargs
166
-
167
- else:
168
- if not isinstance(tools, list):
169
- tools = [tools]
170
- tool_kwarg = {"tools": func_call.lcall(tools, tool_check)}
171
- kwargs = tool_kwarg | kwargs
172
-
173
- return kwargs
174
-
175
-
176
- def func_to_tool(
177
- func_: Callable | list[Callable], parser=None, docstring_style="google"
178
- ):
179
- """
180
- Transforms a given function into a Tool object, equipped with a schema derived
181
- from its docstring. This process involves parsing the function's docstring based
182
- on a specified style ('google' or 'reST') to extract relevant metadata and
183
- parameters, which are then used to construct a comprehensive schema for the Tool.
184
- This schema facilitates the integration of the function with systems or
185
- frameworks that rely on structured metadata for automation, documentation, or
186
- interface generation purposes.
187
-
188
- The function to be transformed can be any Callable that adheres to the
189
- specified docstring conventions. The resulting Tool object encapsulates the
190
- original function, allowing it to be utilized within environments that require
191
- objects with structured metadata.
192
-
193
- Args:
194
- func_ (Callable): The function to be transformed into a Tool object. This
195
- function should have a docstring that follows the
196
- specified docstring style for accurate schema generation.
197
- parser (Optional[Any]): An optional parser object associated with the Tool.
198
- This parameter is currently not utilized in the
199
- transformation process but is included for future
200
- compatibility and extension purposes.
201
- docstring_style (str): The format of the docstring to be parsed, indicating
202
- the convention used in the function's docstring.
203
- Supports 'google' for Google-style docstrings and
204
- 'reST' for reStructuredText-style docstrings. The
205
- chosen style affects how the docstring is parsed and
206
- how the schema is generated.
207
-
208
- Returns:
209
- Tool: An object representing the original function wrapped as a Tool, along
210
- with its generated schema. This Tool object can be used in systems that
211
- require detailed metadata about functions, facilitating tasks such as
212
- automatic documentation generation, user interface creation, or
213
- integration with other software tools.
214
-
215
- Examples:
216
- >>> def example_function_google(param1: int, param2: str) -> bool:
217
- ... '''
218
- ... An example function using Google style docstrings.
219
- ...
220
- ... Args:
221
- ... param1 (int): The first parameter, demonstrating an integer input_.
222
- ... param2 (str): The second parameter, demonstrating a string input_.
223
- ...
224
- ... Returns:
225
- ... bool: A boolean value, illustrating the return type.
226
- ... '''
227
- ... return True
228
- ...
229
- >>> tool_google = func_to_tool(example_function_google, docstring_style='google')
230
- >>> print(isinstance(tool_google, Tool))
231
- True
232
-
233
- >>> def example_function_reST(param1: int, param2: str) -> bool:
234
- ... '''
235
- ... An example function using reStructuredText (reST) style docstrings.
236
- ...
237
- ... :param param1: The first parameter, demonstrating an integer input_.
238
- ... :type param1: int
239
- ... :param param2: The second parameter, demonstrating a string input_.
240
- ... :type param2: str
241
- ... :returns: A boolean value, illustrating the return type.
242
- ... :rtype: bool
243
- ... '''
244
- ... return True
245
- ...
246
- >>> tool_reST = func_to_tool(example_function_reST, docstring_style='reST')
247
- >>> print(isinstance(tool_reST, Tool))
248
- True
249
-
250
- Note:
251
- The transformation process relies heavily on the accuracy and completeness of
252
- the function's docstring. Functions with incomplete or incorrectly formatted
253
- docstrings may result in incomplete or inaccurate Tool schemas.
254
- """
255
-
256
- fs = []
257
- funcs = convert.to_list(func_, flatten=True, dropna=True)
258
- parsers = convert.to_list(parser, flatten=True, dropna=True)
259
-
260
- if parser:
261
- if len(funcs) != len(parsers) != 1:
262
- raise ValueError(
263
- "Length of parser must match length of func. Except if you only pass one"
264
- )
265
-
266
- for idx in range(len(funcs)):
267
- f_ = lambda _f: Tool(
268
- func=_f,
269
- schema_=ParseUtil._func_to_schema(_f, style=docstring_style),
270
- parser=parsers[idx] if len(parsers) > 1 else parsers[0],
271
- )
272
-
273
- fs.append(f_)
274
-
275
- else:
276
- fs = func_call.lcall(
277
- funcs,
278
- lambda _f: Tool(
279
- func=_f, schema_=ParseUtil._func_to_schema(_f, style=docstring_style)
280
- ),
281
- )
282
-
283
- return fs
@@ -1,64 +0,0 @@
1
- from pydantic import Field
2
-
3
- # from lionagi import logging as _logging
4
- from lionagi.core.generic import BaseComponent
5
- from lionagi.experimental.report.util import get_input_output_fields, system_fields
6
-
7
-
8
- class Form(BaseComponent):
9
-
10
- assignment: str = Field(..., examples=["input1, input2 -> output"])
11
-
12
- input_fields: list[str] = Field(default_factory=list)
13
- output_fields: list[str] = Field(default_factory=list)
14
-
15
- def __init__(self, **kwargs):
16
- """
17
- at initialization, all relevant fields if not already provided, are set to None,
18
- not every field is required to be filled, nor required to be declared at initialization
19
- """
20
- super().__init__(**kwargs)
21
- self.input_fields, self.output_fields = get_input_output_fields(self.assignment)
22
- for i in self.input_fields + self.output_fields:
23
- if i not in self.model_fields:
24
- self._add_field(i, value=None)
25
-
26
- @property
27
- def workable(self):
28
- if self.filled:
29
- return False
30
-
31
- for i in self.input_fields:
32
- if not getattr(self, i, None):
33
- return False
34
-
35
- return True
36
-
37
- @property
38
- def work_fields(self):
39
- dict_ = self.to_dict()
40
- return {
41
- k: v
42
- for k, v in dict_.items()
43
- if k not in system_fields and k in self.input_fields + self.output_fields
44
- }
45
-
46
- @property
47
- def filled(self):
48
- return all([value is not None for _, value in self.work_fields.items()])
49
-
50
- def fill(self, form: "Form" = None, **kwargs):
51
- """
52
- only work fields for this form can be filled
53
- a field can only be filled once
54
- """
55
- if self.filled:
56
- raise ValueError("Form is already filled")
57
-
58
- fields = form.work_fields if form else {}
59
- kwargs = {**fields, **kwargs}
60
-
61
- for k, v in kwargs.items():
62
- if k not in self.work_fields:
63
- raise ValueError(f"Field {k} is not a valid work field")
64
- setattr(self, k, v)
@@ -1,138 +0,0 @@
1
- from typing import Any, Type
2
- from pydantic import Field
3
-
4
- # from lionagi import logging as _logging
5
- from lionagi.core.generic import BaseComponent
6
- from lionagi.experimental.report.form import Form
7
- from lionagi.experimental.report.util import get_input_output_fields
8
-
9
-
10
- class Report(BaseComponent):
11
-
12
- assignment: str = Field(..., examples=["input1, input2 -> output"])
13
-
14
- forms: dict[str, Form] = Field(
15
- default_factory=dict,
16
- description="A dictionary of forms related to the report, in {assignment: Form} format.",
17
- )
18
-
19
- form_assignments: list = Field(
20
- [],
21
- description="assignment for the report",
22
- examples=[["a, b -> c", "a -> e", "b -> f", "c -> g", "e, f, g -> h"]],
23
- )
24
-
25
- form_template: Type[Form] = Field(
26
- Form, description="The template for the forms in the report."
27
- )
28
-
29
- input_fields: list[str] = Field(default_factory=list)
30
- output_fields: list[str] = Field(default_factory=list)
31
-
32
- def __init__(self, **kwargs):
33
- """
34
- at initialization, all relevant fields if not already provided, are set to None
35
- """
36
- super().__init__(**kwargs)
37
- self.input_fields, self.output_fields = get_input_output_fields(self.assignment)
38
-
39
- # if assignments is not provided, set it to assignment
40
- if self.form_assignments == []:
41
- self.form_assignments.append(self.assignment)
42
-
43
- # create forms
44
- new_forms = {i: self.form_template(assignment=i) for i in self.form_assignments}
45
-
46
- # add new forms into the report (will ignore new forms already in the
47
- # report with same assignment)
48
- for k, v in new_forms.items():
49
- if k not in self.forms:
50
- self.forms[k] = v
51
-
52
- # if the fields are not declared in the report, add them to report
53
- # with value set to None
54
- for k, v in self.forms.items():
55
- for f in list(v.work_fields.keys()):
56
- if f not in self.model_fields:
57
- field = v.model_fields[f]
58
- self._add_field(f, value=None, field=field)
59
-
60
- # if there are fields in the report that are not in the forms, add them to
61
- # the forms with values
62
- for k, v in self.model_fields.items():
63
- if getattr(self, k, None) is not None:
64
- for f in self.forms.values():
65
- if k in f.work_fields:
66
- f.fill(**{k: getattr(self, k)})
67
-
68
- @property
69
- def work_fields(self) -> dict[str, Any]:
70
- """
71
- all work fields across all forms, including intermediate output fields,
72
- this information is extracted from the forms
73
- """
74
-
75
- all_fields = {}
76
- for form in self.forms.values():
77
- for k, v in form.work_fields.items():
78
- if k not in all_fields:
79
- all_fields[k] = v
80
- return all_fields
81
-
82
- def fill(self, **kwargs):
83
- """
84
- fill the information to both the report and forms
85
- """
86
- kwargs = {**self.work_fields, **kwargs}
87
- for k, v in kwargs.items():
88
- if k in self.work_fields and getattr(self, k, None) is None:
89
- setattr(self, k, v)
90
-
91
- for form in self.forms.values():
92
- if not form.filled:
93
- _kwargs = {k: v for k, v in kwargs.items() if k in form.work_fields}
94
- form.fill(**_kwargs)
95
-
96
- @property
97
- def filled(self):
98
- return all([value is not None for _, value in self.work_fields.items()])
99
-
100
- @property
101
- def workable(self) -> bool:
102
-
103
- if self.filled:
104
- # _logging.info("The report is already filled, no need to work on it.")
105
- return False
106
-
107
- for i in self.input_fields:
108
- if not getattr(self, i, None):
109
- # _logging.error(f"Field '{i}' is required to work on the report.")
110
- return False
111
-
112
- # this is the required fields from report's own assignment
113
- fields = self.input_fields
114
- fields.extend(self.output_fields)
115
-
116
- # if the report's own assignment is not in the forms, return False
117
- for f in fields:
118
- if f not in self.work_fields:
119
- # _logging.error(f"Field {f} is a required deliverable, not found in work field.")
120
- return False
121
-
122
- # get all the output fields from all the forms
123
- outs = []
124
- for form in self.forms.values():
125
- outs.extend(form.output_fields)
126
-
127
- # all output fields should be unique, not a single output field should be
128
- # calculated by more than one form
129
- if len(outs) != len(set(outs)):
130
- # _logging.error("There are duplicate output fields in the forms.")
131
- return False
132
-
133
- return True
134
-
135
- @property
136
- def next_forms(self) -> list[Form] | None:
137
- a = [i for i in self.forms.values() if i.workable]
138
- return a if len(a) > 0 else None
@@ -1,47 +0,0 @@
1
- from lionagi.libs import convert
2
-
3
- system_fields = [
4
- "id_",
5
- "node_id",
6
- "meta",
7
- "metadata",
8
- "timestamp",
9
- "content",
10
- "assignment",
11
- "assignments",
12
- "task",
13
- "template_name",
14
- "version",
15
- "description",
16
- "in_validation_kwargs",
17
- "out_validation_kwargs",
18
- "fix_input",
19
- "fix_output",
20
- "input_fields",
21
- "output_fields",
22
- "choices",
23
- "prompt_fields",
24
- "prompt_fields_annotation",
25
- "instruction_context",
26
- "instruction",
27
- "instruction_output_fields",
28
- "inputs",
29
- "outputs",
30
- "process",
31
- "_validate_field",
32
- "_process_input",
33
- "_process_response",
34
- "_validate_field_choices",
35
- "_validate_input_choices",
36
- "_validate_output_choices",
37
- ]
38
-
39
-
40
- def get_input_output_fields(str_: str) -> list[list[str]]:
41
-
42
- inputs, outputs = str_.split("->")
43
-
44
- input_fields = [convert.strip_lower(i) for i in inputs.split(",")]
45
- output_fields = [convert.strip_lower(o) for o in outputs.split(",")]
46
-
47
- return input_fields, output_fields
@@ -1,43 +0,0 @@
1
- from typing import Any, Callable
2
- from pydantic import BaseModel, Field, field_serializer
3
- from functools import singledispatchmethod
4
- from lionagi.libs import convert
5
-
6
-
7
- class FunctionCalling(BaseModel):
8
- func: Any = Field(..., alias="function")
9
- kwargs: Any = Field({}, alias="arguments")
10
-
11
- @field_serializer("func")
12
- def serialize_func(self, func: Callable):
13
- return func.__name__
14
-
15
- @property
16
- def func_name(self):
17
- return self.func.__name__
18
-
19
- @classmethod
20
- @singledispatchmethod
21
- def create(cls, func_call: Any):
22
- raise TypeError(f"Unsupported type {type(func_call)}")
23
-
24
- @create.register
25
- def _(cls, func_call: tuple):
26
- if len(func_call) == 2:
27
- return cls(func=func_call[0], kwargs=func_call[1])
28
- else:
29
- raise ValueError(f"Invalid tuple length {len(func_call)}")
30
-
31
- @create.register
32
- def _(cls, func_call: dict):
33
- return cls(**func_call)
34
-
35
- @create.register
36
- def _(cls, func_call: str):
37
- try:
38
- return cls(**convert.to_dict(func_call))
39
- except Exception as e:
40
- raise ValueError(f"Invalid string {func_call}") from e
41
-
42
- def __str__(self):
43
- return f"{self.func_name}({self.kwargs})"
@@ -1,66 +0,0 @@
1
- import re
2
- from typing import Dict, Union, Callable, Any
3
-
4
-
5
- class BaseManual:
6
- def __init__(self, template_str: str):
7
- self.template_str = template_str
8
-
9
- def _evaluate_condition(self, match, context):
10
- condition, text = match.groups()
11
- # Future implementations might parse and evaluate the condition more thoroughly
12
- return text if condition in context and context[condition] else ""
13
-
14
- def _render_conditionals(self, context: Dict[str, Union[str, int, float]]) -> str:
15
- conditional_pattern = re.compile(r"\{if (.*?)\}(.*?)\{endif\}", re.DOTALL)
16
- return conditional_pattern.sub(
17
- lambda match: self._evaluate_condition(match, context), self.template_str
18
- )
19
-
20
- def _replace_callable(self, match, context):
21
- key = match.group(1)
22
- if key in context:
23
- value = context[key]
24
- return str(value() if callable(value) else value)
25
- return match.group(0) # Unmatched placeholders remain unchanged.
26
-
27
- def _render_placeholders(
28
- self,
29
- rendered_template: str,
30
- context: Dict[str, Union[str, int, float, Callable]],
31
- ) -> str:
32
- return re.sub(
33
- r"\{(\w+)\}",
34
- lambda match: self._replace_callable(match, context),
35
- rendered_template,
36
- )
37
-
38
- def generate(self, context: Dict[str, Union[str, int, float, Callable]]) -> str:
39
- """
40
- Generates output by first processing conditionals, then rendering placeholders,
41
- including executing callable objects for dynamic data generation.
42
- """
43
- template_with_conditionals = self._render_conditionals(context)
44
- final_output = self._render_placeholders(template_with_conditionals, context)
45
- return final_output
46
-
47
-
48
- # from experiments.executor.executor import SafeEvaluator
49
-
50
- # class DecisionTreeManual:
51
- # def __init__(self, root):
52
- # self.root = root
53
- # self.evaluator = SafeEvaluator()
54
-
55
- # def evaluate(self, context):
56
- # return self._traverse_tree(self.root, context)
57
-
58
- # def _traverse_tree(self, node, context):
59
- # if isinstance(node, CompositeActionNode) or isinstance(node, ActionNode):
60
- # return node.execute(context)
61
- # elif isinstance(node, DecisionNode):
62
- # condition_result = self.evaluator.evaluate(node.condition, context)
63
- # next_node = node.true_branch if condition_result else node.false_branch
64
- # return self._traverse_tree(next_node, context)
65
- # else:
66
- # raise ValueError("Invalid node type.")