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
@@ -0,0 +1,283 @@
1
+ """
2
+ Copyright 2024 HaiyangLi
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ import re
18
+ import json
19
+ import contextlib
20
+
21
+ from lionagi.libs import ParseUtil
22
+ from lionagi.libs.ln_convert import strip_lower, to_dict
23
+ from lionagi.libs.ln_nested import nget
24
+
25
+ from .message import RoledMessage
26
+ from .system import System
27
+ from .instruction import Instruction
28
+ from .assistant_response import AssistantResponse
29
+ from .action_request import ActionRequest
30
+ from .action_response import ActionResponse
31
+
32
+
33
+ def create_message(
34
+ *,
35
+ system=None, # system node - JSON serializable
36
+ instruction=None, # Instruction node - JSON serializable
37
+ context=None, # JSON serializable
38
+ assistant_response=None, # JSON
39
+ function=None,
40
+ arguments=None,
41
+ func_outputs=None,
42
+ action_request=None, # ActionRequest node
43
+ action_response=None, # ActionResponse node
44
+ images=None, # base64 encoded image
45
+ sender=None, # str
46
+ recipient=None, # str
47
+ requested_fields=None, # dict[str, str]
48
+ **kwargs, # additional context fields
49
+ ):
50
+ # order of handling
51
+ # action response - action request - other regular messages
52
+ # if the message is output from function calling we will ignore other message types
53
+ """
54
+ Creates a message based on the provided parameters.
55
+
56
+ Args:
57
+ system (dict, optional): The system node (JSON serializable).
58
+ instruction (dict, optional): The instruction node (JSON serializable).
59
+ context (dict, optional): Additional context (JSON serializable).
60
+ assistant_response (dict, optional): The assistant response node (JSON serializable).
61
+ function (str, optional): The function name for action requests.
62
+ arguments (dict, optional): The arguments for the function.
63
+ func_outputs (Any, optional): The outputs from the function.
64
+ action_request (ActionRequest, optional): The action request node.
65
+ action_response (ActionResponse, optional): The action response node.
66
+ sender (str, optional): The sender of the message.
67
+ recipient (str, optional): The recipient of the message.
68
+ requested_fields (dict[str, str], optional): The requested fields for the instruction.
69
+ **kwargs: Additional context fields.
70
+
71
+ Returns:
72
+ RoledMessage: The constructed message based on the provided parameters.
73
+
74
+ Raises:
75
+ ValueError: If the parameters are invalid or missing required values.
76
+ """
77
+
78
+ if func_outputs or action_response:
79
+ if not action_request:
80
+ raise ValueError(
81
+ "Error: please provide an corresponding action request for an action response."
82
+ )
83
+
84
+ if isinstance(action_response, ActionResponse):
85
+ action_response.update_request(action_request)
86
+ return action_response
87
+
88
+ return ActionResponse(
89
+ action_request=action_request,
90
+ sender=sender,
91
+ func_outputs=func_outputs,
92
+ )
93
+
94
+ if action_request:
95
+ if not isinstance(action_request, ActionRequest):
96
+ raise ValueError(
97
+ "Error: action request must be an instance of ActionRequest."
98
+ )
99
+ return action_request
100
+
101
+ if function:
102
+ if not arguments:
103
+ raise ValueError("Error: please provide arguments for the function.")
104
+ return ActionRequest(
105
+ function=function,
106
+ arguments=arguments,
107
+ sender=sender,
108
+ recipient=recipient,
109
+ )
110
+
111
+ a = {
112
+ "system": system,
113
+ "instruction": instruction,
114
+ "assistant_response": assistant_response,
115
+ }
116
+
117
+ a = {k: v for k, v in a.items() if v is not None}
118
+
119
+ if not len(a) == 1:
120
+ raise ValueError("Error: Message can only have one role")
121
+
122
+ if not func_outputs:
123
+ for k, v in a.items():
124
+ if isinstance(v, RoledMessage):
125
+ if isinstance(v, Instruction):
126
+ if context:
127
+ v._add_context(context)
128
+ if requested_fields:
129
+ v._update_requested_fields(requested_fields)
130
+ return v
131
+
132
+ if system:
133
+ return System(system=system, sender=sender, recipient=recipient)
134
+
135
+ elif assistant_response:
136
+ return AssistantResponse(
137
+ assistant_response=assistant_response,
138
+ sender=sender,
139
+ recipient=recipient,
140
+ )
141
+
142
+ else:
143
+ if images:
144
+ images = images if isinstance(images, list) else [images]
145
+
146
+ return Instruction(
147
+ instruction=instruction,
148
+ context=context,
149
+ sender=sender,
150
+ recipient=recipient,
151
+ requested_fields=requested_fields,
152
+ images=images,
153
+ **kwargs,
154
+ )
155
+
156
+
157
+ def _parse_action_request(response):
158
+ """
159
+ Parses an action request from the response.
160
+
161
+ Args:
162
+ response (dict): The response containing the action request.
163
+
164
+ Returns:
165
+ list[ActionRequest] or None: A list of action requests or None if invalid.
166
+
167
+ Raises:
168
+ ActionError: If the action request is invalid.
169
+ """
170
+ message = to_dict(response) if not isinstance(response, dict) else response
171
+ content_ = None
172
+
173
+ if strip_lower(nget(message, ["content"])) == "none":
174
+ content_ = _handle_action_request(message)
175
+
176
+ elif nget(message, ["content", "tool_uses"], None):
177
+ content_ = message["content"]["tool_uses"]
178
+
179
+ else:
180
+ json_block_pattern = re.compile(r"```json\n({.*?tool_uses.*?})\n```", re.DOTALL)
181
+
182
+ # Find the JSON block in the text
183
+ match = json_block_pattern.search(str(message["content"]))
184
+ if match:
185
+ json_block = match.group(1)
186
+ parsed_json = json.loads(json_block)
187
+ if "tool_uses" in parsed_json:
188
+ content_ = parsed_json["tool_uses"]
189
+ elif "actions" in parsed_json:
190
+ content_ = parsed_json["actions"]
191
+ else:
192
+ content_ = []
193
+
194
+ if isinstance(content_, dict):
195
+ content_ = [content_]
196
+
197
+ if isinstance(content_, list) and not content_ == []:
198
+ outs = []
199
+ for func_calling in content_:
200
+ if "recipient_name" in func_calling:
201
+ func_calling["action"] = func_calling["recipient_name"].split(".")[1]
202
+ func_calling["arguments"] = func_calling["parameters"]
203
+ elif "function" in func_calling:
204
+ func_calling["action"] = func_calling["function"]
205
+ if "parameters" in func_calling:
206
+ func_calling["arguments"] = func_calling["parameters"]
207
+ elif "arguments" in func_calling:
208
+ func_calling["arguments"] = func_calling["arguments"]
209
+
210
+ msg = ActionRequest(
211
+ function=func_calling["action"]
212
+ .replace("action_", "")
213
+ .replace("recipient_", ""),
214
+ arguments=func_calling["arguments"],
215
+ )
216
+ outs.append(msg)
217
+ return outs
218
+
219
+ else:
220
+ try:
221
+ _content = to_dict(message["content"])
222
+ if "action_request" in _content:
223
+ content_ = _content["action_request"]
224
+
225
+ if isinstance(content_, dict):
226
+ content_ = [content_]
227
+
228
+ if isinstance(content_, list):
229
+ outs = []
230
+ for func_calling in content_:
231
+ if "function" in func_calling:
232
+ func_calling["action"] = func_calling["function"]
233
+ if "parameters" in func_calling:
234
+ func_calling["arguments"] = func_calling["parameters"]
235
+ elif "arguments" in func_calling:
236
+ func_calling["arguments"] = func_calling["arguments"]
237
+ msg = ActionRequest(
238
+ function=func_calling["action"]
239
+ .replace("action_", "")
240
+ .replace("recipient_", ""),
241
+ arguments=func_calling["arguments"],
242
+ )
243
+ outs.append(msg)
244
+ return outs
245
+ except:
246
+ return None
247
+ return None
248
+
249
+
250
+ def _handle_action_request(response):
251
+ """
252
+ Handles the action request parsing from the response.
253
+
254
+ Args:
255
+ response (dict): The response containing the action request details.
256
+
257
+ Returns:
258
+ list[dict]: A list of function call details.
259
+
260
+ Raises:
261
+ ValueError: If the response message is invalid.
262
+ """
263
+ try:
264
+ tool_count = 0
265
+ func_list = []
266
+ while tool_count < len(response["tool_calls"]):
267
+ _path = ["tool_calls", tool_count, "type"]
268
+
269
+ if nget(response, _path) == "function":
270
+ _path1 = ["tool_calls", tool_count, "function", "name"]
271
+ _path2 = ["tool_calls", tool_count, "function", "arguments"]
272
+
273
+ func_content = {
274
+ "action": f"action_{nget(response, _path1)}",
275
+ "arguments": nget(response, _path2),
276
+ }
277
+ func_list.append(func_content)
278
+ tool_count += 1
279
+ return func_list
280
+ except:
281
+ raise ValueError(
282
+ "Response message must be one of regular response or function calling"
283
+ )
@@ -0,0 +1,4 @@
1
+ from .form import Form
2
+ from .report import Report
3
+
4
+ __all__ = ["Form", "Report"]
@@ -0,0 +1,217 @@
1
+ """
2
+ Copyright 2024 HaiyangLi
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ """
16
+
17
+ """
18
+ This module defines the BaseForm class, a foundation for form handling in
19
+ applications. It provides common functionalities for form operations like
20
+ initialization, validation, and state management. Extend this class to
21
+ implement specific form behaviors and configurations.
22
+ """
23
+
24
+ from abc import abstractmethod
25
+ from typing import Any, List, Dict
26
+ import contextlib
27
+ from lionagi.core.collections.abc import Component, Field
28
+ from ..collections.util import to_list_type
29
+
30
+
31
+ class BaseForm(Component):
32
+ """
33
+ NOTICE:
34
+ The Form/Report system is inspired by DSPy. (especially in DSPy's usage
35
+ of `Signature` and `Module`)
36
+ https://github.com/stanfordnlp/dspy
37
+
38
+ MIT License
39
+ Copyright (c) 2023 Stanford Future Data Systems
40
+
41
+ Permission is hereby granted, free of charge, to any person obtaining a copy
42
+ of this software and associated documentation files (the "Software"), to deal
43
+ in the Software without restriction, including without limitation the rights
44
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
45
+ copies of the Software, and to permit persons to whom the Software is
46
+ furnished to do so, subject to the following conditions:
47
+
48
+ The above copyright notice and this permission notice shall be included in all
49
+ copies or substantial portions of the Software.
50
+
51
+ REFERENCES:
52
+ @article{khattab2023dspy,
53
+ title={DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines},
54
+ author={Khattab, Omar and Singhvi, Arnav and Maheshwari, Paridhi and Zhang, Zhiyuan and
55
+ Santhanam, Keshav and Vardhamanan, Sri and Haq, Saiful and Sharma, Ashutosh and Joshi,
56
+ Thomas T. and Moazam, Hanna and Miller, Heather and Zaharia, Matei and Potts, Christopher},
57
+ journal={arXiv preprint arXiv:2310.03714},
58
+ year={2023}
59
+ }
60
+ @article{khattab2022demonstrate,
61
+ title={Demonstrate-Search-Predict: Composing Retrieval and Language Models for
62
+ Knowledge-Intensive {NLP}},
63
+ author={Khattab, Omar and Santhanam, Keshav and Li, Xiang Lisa and Hall, David and Liang,
64
+ Percy and Potts, Christopher and Zaharia, Matei},
65
+ journal={arXiv preprint arXiv:2212.14024},
66
+ year={2022}
67
+ }
68
+
69
+ LionAGI Modifications:
70
+ - Redesigned focusing on form-based task handling
71
+ - fully integrated with LionAGI's existing collections and components
72
+ - developed report system for multi-step task handling
73
+ - created work system for task execution and management
74
+
75
+ Base class for handling form-like structures within an application.
76
+ Manages form components and operations such as filling forms and
77
+ checking their state (filled, workable).
78
+
79
+ Attributes:
80
+ assignment (str): The objective of the form specifying input/output fields.
81
+ input_fields (List[str]): Fields required to carry out the objective of the form.
82
+ requested_fields (List[str]): Fields requested to be filled by the user.
83
+ task (Any): The work to be done by the form, including custom instructions.
84
+ validation_kwargs (Dict[str, Dict[str, Any]]): Additional validation constraints for the form fields.
85
+ """
86
+
87
+ template_name: str = "default_directive"
88
+
89
+ assignment: str | None = Field(
90
+ None,
91
+ description="The objective of the form specifying input/output fields.",
92
+ examples=["input1, input2 -> output"],
93
+ )
94
+
95
+ input_fields: List[str] = Field(
96
+ default_factory=list,
97
+ description="Fields required to carry out the objective of the form.",
98
+ )
99
+
100
+ requested_fields: List[str] = Field(
101
+ default_factory=list,
102
+ description="Fields requested to be filled by the user.",
103
+ )
104
+
105
+ task: Any = Field(
106
+ default_factory=str,
107
+ description="The work to be done by the form, including custom instructions.",
108
+ )
109
+
110
+ validation_kwargs: Dict[str, Dict[str, Any]] = Field(
111
+ default_factory=dict,
112
+ description="Additional validation constraints for the form fields.",
113
+ examples=[{"field": {"config1": "a", "config2": "b"}}],
114
+ )
115
+
116
+ @property
117
+ def work_fields(self) -> Dict[str, Any]:
118
+ """
119
+ Get the fields relevant to the current task, including input and
120
+ requested fields. Must be implemented by subclasses.
121
+
122
+ Returns:
123
+ Dict[str, Any]: The fields relevant to the current task.
124
+ """
125
+ raise NotImplementedError
126
+
127
+ @abstractmethod
128
+ def fill(self, *args, **kwargs):
129
+ """
130
+ Fill the form from various sources, including other forms and
131
+ additional fields. Implement this method in subclasses.
132
+
133
+ Args:
134
+ *args: Additional positional arguments.
135
+ **kwargs: Additional keyword arguments.
136
+ """
137
+ pass
138
+
139
+ @abstractmethod
140
+ def is_workable(self) -> bool:
141
+ """
142
+ Check if the form object is ready for work execution. Raise an error
143
+ if the form is not workable. Use with the workable property.
144
+
145
+ Returns:
146
+ bool: True if the form is workable, otherwise False.
147
+ """
148
+ pass
149
+
150
+ @property
151
+ def filled(self) -> bool:
152
+ """
153
+ Check if the form is filled with all required fields. Uses the
154
+ _is_filled method and suppresses any ValueError raised by it.
155
+
156
+ Returns:
157
+ bool: True if the form is filled, otherwise False.
158
+ """
159
+ with contextlib.suppress(ValueError):
160
+ return self._is_filled()
161
+ return False
162
+
163
+ @property
164
+ def workable(self) -> bool:
165
+ """
166
+ Check if the form is workable. This property does not raise an error
167
+ and will return True or False.
168
+
169
+ Returns:
170
+ bool: True if the form is workable, otherwise False.
171
+ """
172
+ with contextlib.suppress(ValueError):
173
+ return self.is_workable()
174
+ return False
175
+
176
+ def _is_filled(self) -> bool:
177
+ """
178
+ Private method to check if all work fields are filled. Raises a
179
+ ValueError if any field is not filled.
180
+
181
+ Returns:
182
+ bool: True if all work fields are filled, otherwise raises ValueError.
183
+
184
+ Raises:
185
+ ValueError: If any field is not filled.
186
+ """
187
+ for k, value in self.work_fields.items():
188
+ if value is None:
189
+ raise ValueError(f"Field {k} is not filled")
190
+ return True
191
+
192
+ def _get_all_fields(
193
+ self, form: List["BaseForm"] = None, **kwargs
194
+ ) -> Dict[str, Any]:
195
+ """
196
+ Given a form or collections of forms, and additional fields, gather
197
+ all fields together including self fields with valid value.
198
+
199
+ Args:
200
+ form (List[BaseForm], optional): A list of forms to gather fields from.
201
+ **kwargs: Additional fields to include.
202
+
203
+ Returns:
204
+ Dict[str, Any]: A dictionary of all gathered fields.
205
+ """
206
+ form: list["BaseForm"] = to_list_type(form) if form else []
207
+ all_fields = self.work_fields.copy()
208
+ all_form_fields = (
209
+ {}
210
+ if not form
211
+ else {k: v for i in form for k, v in i.work_fields.items() if v is not None}
212
+ )
213
+ all_fields.update({**all_form_fields, **kwargs})
214
+ return all_fields
215
+
216
+ def copy(self):
217
+ return self.model_copy()