lionagi 0.1.2__py3-none-any.whl → 0.2.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 (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 +76 -0
  94. lionagi/core/work/work_function.py +101 -0
  95. lionagi/core/work/work_queue.py +103 -0
  96. lionagi/core/work/worker.py +258 -0
  97. lionagi/core/work/worklog.py +120 -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.1.dist-info/LICENSE +202 -0
  168. lionagi-0.2.1.dist-info/METADATA +272 -0
  169. lionagi-0.2.1.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.1.dist-info}/WHEEL +0 -0
  268. {lionagi-0.1.2.dist-info → lionagi-0.2.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,35 @@
1
+ # from lionagi.libs.ln_convert import is_same_dtype
2
+ # from collections.abc import Mapping, Generator
3
+
4
+
5
+ # def validate_keys(keys):
6
+ # """
7
+ # choices can be provided from various sources:
8
+ # - mapping such as dict, their keys will be used as choices
9
+ # - iterables including list, tuple, set, generator, enum, etc.
10
+ # - strings, comma separated values
11
+ # """
12
+
13
+ # try:
14
+ # if isinstance(keys, Mapping):
15
+ # keys = list(keys.keys())
16
+
17
+ # elif isinstance(keys, (list, tuple, set, Generator)):
18
+ # keys = set(keys)
19
+
20
+ # elif isinstance(keys, str):
21
+ # if "," in keys:
22
+ # keys = list({i.strip() for i in keys.split(",")})
23
+ # else:
24
+ # keys = [keys.strip()]
25
+
26
+ # else:
27
+ # keys = [i.value for i in keys]
28
+
29
+ # except Exception as e:
30
+ # raise ValueError(f"invalid choices {keys}") from e
31
+
32
+ # if not is_same_dtype(keys):
33
+ # raise ValueError(f"choices must be of the same type, got {keys}")
34
+
35
+ # return keys
@@ -0,0 +1,431 @@
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
+ from typing import Any
18
+ from lionagi.libs.ln_convert import is_same_dtype, to_df
19
+ from lionagi.core.collections.abc import Field
20
+ from lionagi.core.collections import (
21
+ pile,
22
+ progression,
23
+ Pile,
24
+ Progression,
25
+ iModel,
26
+ Exchange,
27
+ )
28
+ from lionagi.core.generic.node import Node
29
+ from lionagi.core.action import Tool, ToolManager
30
+ from lionagi.core.mail import Mail, Package
31
+ from lionagi.core.message import (
32
+ create_message,
33
+ System,
34
+ Instruction,
35
+ AssistantResponse,
36
+ ActionRequest,
37
+ ActionResponse,
38
+ RoledMessage,
39
+ )
40
+
41
+ from lionagi.core.session.directive_mixin import DirectiveMixin
42
+
43
+
44
+ class Branch(Node, DirectiveMixin):
45
+ """
46
+ A class representing a branch in a messaging system.
47
+
48
+ Attributes:
49
+ messages (Pile): A pile of messages.
50
+ progress (Progression): A progression of messages.
51
+ tool_manager (ToolManager): A manager for handling tools.
52
+ system (System): The system associated with the branch.
53
+ user (str): The user associated with the branch.
54
+ mailbox (Exchange): An exchange for managing mail.
55
+ imodel (iModel): The model associated with the branch.
56
+ """
57
+
58
+ messages: Pile = Field(None)
59
+ progress: Progression = Field(None)
60
+ tool_manager: ToolManager = Field(None)
61
+ system: System = Field(None)
62
+ user: str = Field(None)
63
+ mailbox: Exchange[Mail] = Field(None)
64
+ imodel: iModel = Field(None)
65
+
66
+ def __init__(
67
+ self,
68
+ system: System | None = None,
69
+ system_sender: str | None = None,
70
+ user: str | None = None,
71
+ messages: Pile = None,
72
+ progress: Progression = None,
73
+ tool_manager: ToolManager = None,
74
+ tools: Any = None,
75
+ imodel=None,
76
+ ):
77
+ """
78
+ Initializes a new instance of the Branch class.
79
+
80
+ Args:
81
+ system (System, optional): The system associated with the branch.
82
+ system_sender (str, optional): The sender of the system message.
83
+ user (str, optional): The user associated with the branch.
84
+ messages (Pile, optional): A pile of messages.
85
+ progress (Progression, optional): A progression of messages.
86
+ tool_manager (ToolManager, optional): A manager for handling tools.
87
+ tools (Any, optional): Tools to be registered with the tool manager.
88
+ imodel (iModel, optional): The model associated with the branch.
89
+ """
90
+ super().__init__()
91
+ self.system = None
92
+
93
+ self.user = user or "user"
94
+ self.messages = messages or pile({})
95
+ self.progress = progress or progression()
96
+ self.tool_manager = tool_manager or ToolManager()
97
+ self.mailbox = Exchange()
98
+ self.imodel = imodel or iModel()
99
+ if tools:
100
+ self.tool_manager.register_tools(tools)
101
+ self.set_system(system=system, sender=system_sender)
102
+ # system = system or "You are a helpful assistant, let's think step by step"
103
+ # self.add_message(system=system, sender=system_sender)
104
+
105
+ def set_system(self, system=None, sender=None) -> None:
106
+ """
107
+ Sets the system message.
108
+
109
+ Args:
110
+ system (System): The system message to set.
111
+ sender (str, optional): The sender of the system message.
112
+ """
113
+ system = system or "You are a helpful assistant."
114
+ if len(self.progress) == 0:
115
+ self.add_message(system=system, sender=sender)
116
+ else:
117
+ _msg = System(system=system, sender=sender)
118
+ _msg.recipient = self.ln_id
119
+ self._remove_system()
120
+ self.system = _msg
121
+
122
+ def add_message(
123
+ self,
124
+ *,
125
+ system=None, # system node - JSON serializable
126
+ instruction=None, # Instruction node - JSON serializable
127
+ context=None, # JSON serializable
128
+ assistant_response=None, # JSON
129
+ function=None,
130
+ arguments=None,
131
+ func_outputs=None,
132
+ action_request=None, # ActionRequest node
133
+ action_response=None, # ActionResponse node
134
+ images=None,
135
+ sender=None, # str
136
+ recipient=None, # str
137
+ requested_fields=None, # dict[str, str]
138
+ metadata: dict | None = None, # extra metadata
139
+ **kwargs, # additional context fields
140
+ ) -> bool:
141
+ """
142
+ Adds a message to the branch.
143
+
144
+ Args:
145
+ system (Any, optional): The system node (JSON serializable).
146
+ instruction (Any, optional): The instruction node (JSON serializable).
147
+ context (Any, optional): Additional context (JSON serializable).
148
+ assistant_response (Any, optional): The assistant's response (JSON serializable).
149
+ function (Any, optional): The function associated with the message.
150
+ arguments (Any, optional): The arguments for the function.
151
+ func_outputs (Any, optional): The outputs of the function.
152
+ action_request (Any, optional): The action request node.
153
+ action_response (Any, optional): The action response node.
154
+ sender (str, optional): The sender of the message.
155
+ recipient (str, optional): The recipient of the message.
156
+ requested_fields (dict[str, str], optional): Requested fields for the message.
157
+ metadata (dict, optional): Extra metadata for the message.
158
+ **kwargs: Additional context fields.
159
+
160
+ Returns:
161
+ bool: True if the message was successfully added, else False.
162
+ """
163
+ if assistant_response:
164
+ sender = self.ln_id
165
+
166
+ _msg = create_message(
167
+ system=system,
168
+ instruction=instruction,
169
+ context=context,
170
+ assistant_response=assistant_response,
171
+ function=function,
172
+ arguments=arguments,
173
+ func_outputs=func_outputs,
174
+ action_request=action_request,
175
+ action_response=action_response,
176
+ sender=sender,
177
+ images=images,
178
+ recipient=recipient,
179
+ requested_fields=requested_fields,
180
+ **kwargs,
181
+ )
182
+
183
+ if isinstance(_msg, System):
184
+ _msg.recipient = self.ln_id # the branch itself, system is to the branch
185
+ self._remove_system()
186
+ self.system = _msg
187
+
188
+ if isinstance(_msg, Instruction):
189
+ _msg.sender = sender or self.user
190
+ _msg.recipient = recipient or self.ln_id
191
+
192
+ if isinstance(_msg, AssistantResponse):
193
+ _msg.sender = sender or self.ln_id
194
+ _msg.recipient = recipient or "user"
195
+
196
+ if isinstance(_msg, ActionRequest):
197
+ _msg.sender = sender or self.ln_id
198
+ _msg.recipient = recipient or "N/A"
199
+
200
+ if isinstance(_msg, ActionResponse):
201
+ _msg.sender = sender or "N/A"
202
+ _msg.recipient = recipient or self.ln_id
203
+
204
+ if metadata:
205
+ _msg._meta_insert(["extra"], metadata)
206
+
207
+ return self.messages.include(_msg) and self.progress.include(_msg)
208
+
209
+ def to_chat_messages(self) -> list[dict[str, Any]]:
210
+ """
211
+ Converts the messages to chat message format.
212
+
213
+ Returns:
214
+ list[dict[str, Any]]: A list of chat messages.
215
+ """
216
+ return [self.messages[j].chat_msg for j in self.progress]
217
+
218
+ def _remove_system(self) -> None:
219
+ """
220
+ Removes the system message from the branch.
221
+ """
222
+ self.messages.exclude(self.system)
223
+ self.progress.exclude(self.system)
224
+ self.system = None
225
+
226
+ def clear(self) -> None:
227
+ """
228
+ Clears all messages and progression in the branch.
229
+ """
230
+ self.messages.clear()
231
+ self.progress.clear()
232
+
233
+ @property
234
+ def has_tools(self) -> bool:
235
+ """
236
+ Checks if the branch has tools.
237
+
238
+ Returns:
239
+ bool: True if the branch has tools, else False.
240
+ """
241
+ return self.tool_manager.registry != {}
242
+
243
+ def register_tools(self, tools) -> None:
244
+ """
245
+ Registers tools with the tool manager.
246
+
247
+ Args:
248
+ tools (Any): The tools to register.
249
+ """
250
+ self.tool_manager.register_tools(tools=tools)
251
+
252
+ def delete_tools(self, tools, verbose: bool = True) -> bool:
253
+ """
254
+ Deletes tools from the tool manager.
255
+
256
+ Args:
257
+ tools (Any): The tools to delete.
258
+ verbose (bool, optional): Whether to print deletion status.
259
+
260
+ Returns:
261
+ bool: True if tools were successfully deleted, else False.
262
+ """
263
+ if not isinstance(tools, list):
264
+ tools = [tools]
265
+ if is_same_dtype(tools, str):
266
+ for act_ in tools:
267
+ if act_ in self.tool_manager.registry:
268
+ self.tool_manager.registry.pop(act_)
269
+ if verbose:
270
+ print("tools successfully deleted")
271
+ return True
272
+ elif is_same_dtype(tools, Tool):
273
+ for act_ in tools:
274
+ if act_.schema_["function"]["name"] in self.tool_manager.registry:
275
+ self.tool_manager.registry.pop(act_.schema_["function"]["name"])
276
+ if verbose:
277
+ print("tools successfully deleted")
278
+ return True
279
+ if verbose:
280
+ print("tools deletion failed")
281
+ return False
282
+
283
+ def update_last_instruction_meta(self, meta):
284
+ """
285
+ Updates metadata of the last instruction.
286
+
287
+ Args:
288
+ meta (dict): The metadata to update.
289
+ """
290
+
291
+ for i in reversed(self.progress):
292
+ if isinstance(self.messages[i], Instruction):
293
+ self.messages[i]._meta_insert(["extra"], meta)
294
+ return
295
+
296
+ @property
297
+ def last_response(self):
298
+ for i in reversed(self.progress):
299
+ if isinstance(self.messages[i], AssistantResponse):
300
+ return self.messages[i]
301
+
302
+ @property
303
+ def assistant_responses(self):
304
+ return pile(
305
+ [
306
+ self.messages[i]
307
+ for i in self.progress
308
+ if isinstance(self.messages[i], AssistantResponse)
309
+ ]
310
+ )
311
+
312
+ def to_df(self) -> Any:
313
+ """
314
+ Converts the messages to a DataFrame.
315
+
316
+ Returns:
317
+ Any: A DataFrame representation of the messages.
318
+ """
319
+ fields = [
320
+ "ln_id",
321
+ "message_type",
322
+ "timestamp",
323
+ "role",
324
+ "content",
325
+ "metadata",
326
+ "sender",
327
+ "recipient",
328
+ ]
329
+ dicts_ = []
330
+ for i in self.progress:
331
+ _d = {}
332
+ for j in fields:
333
+ _d.update({j: getattr(self.messages[i], j, None)})
334
+ _d["message_type"] = self.messages[i].class_name
335
+ dicts_.append(_d)
336
+
337
+ return to_df(dicts_)
338
+
339
+ def _is_invoked(self) -> bool:
340
+ """
341
+ Checks if the last message is an ActionResponse.
342
+
343
+ Returns:
344
+ bool: True if the last message is an ActionResponse, else False.
345
+ """
346
+ return isinstance(self.messages[-1], ActionResponse)
347
+
348
+ def send(
349
+ self, recipient: str, category: str, package: Any, request_source: str = None
350
+ ) -> None:
351
+ """
352
+ Sends a mail to a recipient.
353
+
354
+ Args:
355
+ recipient (str): The ID of the recipient.
356
+ category (str): The category of the mail.
357
+ package (Any): The package to send in the mail.
358
+ request_source (str): The source of the request.
359
+ """
360
+ pack = Package(
361
+ category=category, package=package, request_source=request_source
362
+ )
363
+ mail = Mail(
364
+ sender=self.ln_id,
365
+ recipient=recipient,
366
+ package=pack,
367
+ )
368
+ self.mailbox.include(mail, "out")
369
+
370
+ def receive(
371
+ self,
372
+ sender: str,
373
+ message: bool = True,
374
+ tool: bool = True,
375
+ imodel: bool = True,
376
+ ) -> None:
377
+ """
378
+ Receives mail from a sender.
379
+
380
+ Args:
381
+ sender (str): The ID of the sender.
382
+ message (bool, optional): Whether to process message mails. Defaults to True.
383
+ tool (bool, optional): Whether to process tool mails. Defaults to True.
384
+ imodel (bool, optional): Whether to process imodel mails. Defaults to True.
385
+
386
+ Raises:
387
+ ValueError: If the sender does not exist or the mail category is invalid.
388
+ """
389
+ skipped_requests = progression()
390
+ if sender not in self.mailbox.pending_ins.keys():
391
+ raise ValueError(f"No package from {sender}")
392
+ while self.mailbox.pending_ins[sender].size() > 0:
393
+ mail_id = self.mailbox.pending_ins[sender].popleft()
394
+ mail: Mail = self.mailbox.pile[mail_id]
395
+
396
+ if mail.category == "message" and message:
397
+ if not isinstance(mail.package.package, RoledMessage):
398
+ raise ValueError("Invalid message format")
399
+ new_message = mail.package.package.clone()
400
+ new_message.sender = mail.sender
401
+ new_message.recipient = self.ln_id
402
+ self.messages.include(new_message)
403
+ self.progress.include(new_message)
404
+ self.mailbox.pile.pop(mail_id)
405
+
406
+ elif mail.category == "tool" and tool:
407
+ if not isinstance(mail.package.package, Tool):
408
+ raise ValueError("Invalid tools format")
409
+ self.tool_manager.register_tools(mail.package.package)
410
+ self.mailbox.pile.pop(mail_id)
411
+
412
+ elif mail.category == "imodel" and imodel:
413
+ if not isinstance(mail.package.package, iModel):
414
+ raise ValueError("Invalid iModel format")
415
+ self.imodel = mail.package.package
416
+ self.mailbox.pile.pop(mail_id)
417
+
418
+ else:
419
+ skipped_requests.append(mail)
420
+
421
+ self.mailbox.pending_ins[sender] = skipped_requests
422
+
423
+ if self.mailbox.pending_ins[sender].size() == 0:
424
+ self.mailbox.pending_ins.pop(sender)
425
+
426
+ def receive_all(self) -> None:
427
+ """
428
+ Receives mail from all senders.
429
+ """
430
+ for key in list(self.mailbox.pending_ins.keys()):
431
+ self.receive(key)