lionagi 0.0.312__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 +61 -3
  2. lionagi/core/__init__.py +0 -14
  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/__init__.py +0 -3
  11. lionagi/core/agent/base_agent.py +45 -36
  12. lionagi/core/agent/eval/evaluator.py +1 -0
  13. lionagi/core/agent/eval/vote.py +40 -0
  14. lionagi/core/agent/learn/learner.py +59 -0
  15. lionagi/core/agent/plan/unit_template.py +1 -0
  16. lionagi/core/collections/__init__.py +17 -0
  17. lionagi/core/collections/_logger.py +319 -0
  18. lionagi/core/collections/abc/__init__.py +53 -0
  19. lionagi/core/collections/abc/component.py +615 -0
  20. lionagi/core/collections/abc/concepts.py +297 -0
  21. lionagi/core/collections/abc/exceptions.py +150 -0
  22. lionagi/core/collections/abc/util.py +45 -0
  23. lionagi/core/collections/exchange.py +161 -0
  24. lionagi/core/collections/flow.py +426 -0
  25. lionagi/core/collections/model.py +419 -0
  26. lionagi/core/collections/pile.py +913 -0
  27. lionagi/core/collections/progression.py +236 -0
  28. lionagi/core/collections/util.py +64 -0
  29. lionagi/core/director/direct.py +314 -0
  30. lionagi/core/director/director.py +2 -0
  31. lionagi/core/engine/branch_engine.py +333 -0
  32. lionagi/core/engine/instruction_map_engine.py +204 -0
  33. lionagi/core/engine/sandbox_.py +14 -0
  34. lionagi/core/engine/script_engine.py +99 -0
  35. lionagi/core/executor/base_executor.py +90 -0
  36. lionagi/core/executor/graph_executor.py +330 -0
  37. lionagi/core/executor/neo4j_executor.py +384 -0
  38. lionagi/core/generic/__init__.py +7 -0
  39. lionagi/core/generic/edge.py +112 -0
  40. lionagi/core/generic/edge_condition.py +16 -0
  41. lionagi/core/generic/graph.py +236 -0
  42. lionagi/core/generic/hyperedge.py +1 -0
  43. lionagi/core/generic/node.py +220 -0
  44. lionagi/core/generic/tree.py +48 -0
  45. lionagi/core/generic/tree_node.py +79 -0
  46. lionagi/core/mail/__init__.py +7 -3
  47. lionagi/core/mail/mail.py +25 -0
  48. lionagi/core/mail/mail_manager.py +142 -58
  49. lionagi/core/mail/package.py +45 -0
  50. lionagi/core/mail/start_mail.py +36 -0
  51. lionagi/core/message/__init__.py +19 -0
  52. lionagi/core/message/action_request.py +133 -0
  53. lionagi/core/message/action_response.py +135 -0
  54. lionagi/core/message/assistant_response.py +95 -0
  55. lionagi/core/message/instruction.py +234 -0
  56. lionagi/core/message/message.py +101 -0
  57. lionagi/core/message/system.py +86 -0
  58. lionagi/core/message/util.py +283 -0
  59. lionagi/core/report/__init__.py +4 -0
  60. lionagi/core/report/base.py +217 -0
  61. lionagi/core/report/form.py +231 -0
  62. lionagi/core/report/report.py +166 -0
  63. lionagi/core/report/util.py +28 -0
  64. lionagi/core/rule/__init__.py +0 -0
  65. lionagi/core/rule/_default.py +16 -0
  66. lionagi/core/rule/action.py +99 -0
  67. lionagi/core/rule/base.py +238 -0
  68. lionagi/core/rule/boolean.py +56 -0
  69. lionagi/core/rule/choice.py +47 -0
  70. lionagi/core/rule/mapping.py +96 -0
  71. lionagi/core/rule/number.py +71 -0
  72. lionagi/core/rule/rulebook.py +109 -0
  73. lionagi/core/rule/string.py +52 -0
  74. lionagi/core/rule/util.py +35 -0
  75. lionagi/core/session/__init__.py +0 -3
  76. lionagi/core/session/branch.py +431 -0
  77. lionagi/core/session/directive_mixin.py +287 -0
  78. lionagi/core/session/session.py +230 -902
  79. lionagi/core/structure/__init__.py +1 -0
  80. lionagi/core/structure/chain.py +1 -0
  81. lionagi/core/structure/forest.py +1 -0
  82. lionagi/core/structure/graph.py +1 -0
  83. lionagi/core/structure/tree.py +1 -0
  84. lionagi/core/unit/__init__.py +5 -0
  85. lionagi/core/unit/parallel_unit.py +245 -0
  86. lionagi/core/unit/template/__init__.py +0 -0
  87. lionagi/core/unit/template/action.py +81 -0
  88. lionagi/core/unit/template/base.py +51 -0
  89. lionagi/core/unit/template/plan.py +84 -0
  90. lionagi/core/unit/template/predict.py +109 -0
  91. lionagi/core/unit/template/score.py +124 -0
  92. lionagi/core/unit/template/select.py +104 -0
  93. lionagi/core/unit/unit.py +362 -0
  94. lionagi/core/unit/unit_form.py +305 -0
  95. lionagi/core/unit/unit_mixin.py +1168 -0
  96. lionagi/core/unit/util.py +71 -0
  97. lionagi/core/validator/__init__.py +0 -0
  98. lionagi/core/validator/validator.py +364 -0
  99. lionagi/core/work/__init__.py +0 -0
  100. lionagi/core/work/work.py +76 -0
  101. lionagi/core/work/work_function.py +101 -0
  102. lionagi/core/work/work_queue.py +103 -0
  103. lionagi/core/work/worker.py +258 -0
  104. lionagi/core/work/worklog.py +120 -0
  105. lionagi/experimental/__init__.py +0 -0
  106. lionagi/experimental/compressor/__init__.py +0 -0
  107. lionagi/experimental/compressor/base.py +46 -0
  108. lionagi/experimental/compressor/llm_compressor.py +247 -0
  109. lionagi/experimental/compressor/llm_summarizer.py +61 -0
  110. lionagi/experimental/compressor/util.py +70 -0
  111. lionagi/experimental/directive/__init__.py +19 -0
  112. lionagi/experimental/directive/parser/__init__.py +0 -0
  113. lionagi/experimental/directive/parser/base_parser.py +282 -0
  114. lionagi/experimental/directive/template/__init__.py +0 -0
  115. lionagi/experimental/directive/template/base_template.py +79 -0
  116. lionagi/experimental/directive/template/schema.py +36 -0
  117. lionagi/experimental/directive/tokenizer.py +73 -0
  118. lionagi/experimental/evaluator/__init__.py +0 -0
  119. lionagi/experimental/evaluator/ast_evaluator.py +131 -0
  120. lionagi/experimental/evaluator/base_evaluator.py +218 -0
  121. lionagi/experimental/knowledge/__init__.py +0 -0
  122. lionagi/experimental/knowledge/base.py +10 -0
  123. lionagi/experimental/knowledge/graph.py +0 -0
  124. lionagi/experimental/memory/__init__.py +0 -0
  125. lionagi/experimental/strategies/__init__.py +0 -0
  126. lionagi/experimental/strategies/base.py +1 -0
  127. lionagi/integrations/bridge/autogen_/__init__.py +0 -0
  128. lionagi/integrations/bridge/autogen_/autogen_.py +124 -0
  129. lionagi/integrations/bridge/langchain_/documents.py +4 -0
  130. lionagi/integrations/bridge/llamaindex_/index.py +30 -0
  131. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
  132. lionagi/integrations/bridge/llamaindex_/llama_pack.py +227 -0
  133. lionagi/integrations/bridge/llamaindex_/node_parser.py +6 -9
  134. lionagi/integrations/bridge/pydantic_/pydantic_bridge.py +1 -0
  135. lionagi/integrations/bridge/transformers_/__init__.py +0 -0
  136. lionagi/integrations/bridge/transformers_/install_.py +36 -0
  137. lionagi/integrations/chunker/__init__.py +0 -0
  138. lionagi/integrations/chunker/chunk.py +312 -0
  139. lionagi/integrations/config/oai_configs.py +38 -7
  140. lionagi/integrations/config/ollama_configs.py +1 -1
  141. lionagi/integrations/config/openrouter_configs.py +14 -2
  142. lionagi/integrations/loader/__init__.py +0 -0
  143. lionagi/integrations/loader/load.py +253 -0
  144. lionagi/integrations/loader/load_util.py +195 -0
  145. lionagi/integrations/provider/_mapping.py +46 -0
  146. lionagi/integrations/provider/litellm.py +2 -1
  147. lionagi/integrations/provider/mlx_service.py +16 -9
  148. lionagi/integrations/provider/oai.py +91 -4
  149. lionagi/integrations/provider/ollama.py +7 -6
  150. lionagi/integrations/provider/openrouter.py +115 -8
  151. lionagi/integrations/provider/services.py +2 -2
  152. lionagi/integrations/provider/transformers.py +18 -22
  153. lionagi/integrations/storage/__init__.py +3 -0
  154. lionagi/integrations/storage/neo4j.py +665 -0
  155. lionagi/integrations/storage/storage_util.py +287 -0
  156. lionagi/integrations/storage/structure_excel.py +285 -0
  157. lionagi/integrations/storage/to_csv.py +63 -0
  158. lionagi/integrations/storage/to_excel.py +83 -0
  159. lionagi/libs/__init__.py +26 -1
  160. lionagi/libs/ln_api.py +78 -23
  161. lionagi/libs/ln_context.py +37 -0
  162. lionagi/libs/ln_convert.py +21 -9
  163. lionagi/libs/ln_func_call.py +69 -28
  164. lionagi/libs/ln_image.py +107 -0
  165. lionagi/libs/ln_knowledge_graph.py +405 -0
  166. lionagi/libs/ln_nested.py +26 -11
  167. lionagi/libs/ln_parse.py +110 -14
  168. lionagi/libs/ln_queue.py +117 -0
  169. lionagi/libs/ln_tokenize.py +164 -0
  170. lionagi/{core/prompt/field_validator.py → libs/ln_validate.py} +79 -14
  171. lionagi/libs/special_tokens.py +172 -0
  172. lionagi/libs/sys_util.py +107 -2
  173. lionagi/lions/__init__.py +0 -0
  174. lionagi/lions/coder/__init__.py +0 -0
  175. lionagi/lions/coder/add_feature.py +20 -0
  176. lionagi/lions/coder/base_prompts.py +22 -0
  177. lionagi/lions/coder/code_form.py +13 -0
  178. lionagi/lions/coder/coder.py +168 -0
  179. lionagi/lions/coder/util.py +96 -0
  180. lionagi/lions/researcher/__init__.py +0 -0
  181. lionagi/lions/researcher/data_source/__init__.py +0 -0
  182. lionagi/lions/researcher/data_source/finhub_.py +191 -0
  183. lionagi/lions/researcher/data_source/google_.py +199 -0
  184. lionagi/lions/researcher/data_source/wiki_.py +96 -0
  185. lionagi/lions/researcher/data_source/yfinance_.py +21 -0
  186. lionagi/tests/integrations/__init__.py +0 -0
  187. lionagi/tests/libs/__init__.py +0 -0
  188. lionagi/tests/libs/test_field_validators.py +353 -0
  189. lionagi/tests/{test_libs → libs}/test_func_call.py +23 -21
  190. lionagi/tests/{test_libs → libs}/test_nested.py +36 -21
  191. lionagi/tests/{test_libs → libs}/test_parse.py +1 -1
  192. lionagi/tests/libs/test_queue.py +67 -0
  193. lionagi/tests/test_core/collections/__init__.py +0 -0
  194. lionagi/tests/test_core/collections/test_component.py +206 -0
  195. lionagi/tests/test_core/collections/test_exchange.py +138 -0
  196. lionagi/tests/test_core/collections/test_flow.py +145 -0
  197. lionagi/tests/test_core/collections/test_pile.py +171 -0
  198. lionagi/tests/test_core/collections/test_progression.py +129 -0
  199. lionagi/tests/test_core/generic/__init__.py +0 -0
  200. lionagi/tests/test_core/generic/test_edge.py +67 -0
  201. lionagi/tests/test_core/generic/test_graph.py +96 -0
  202. lionagi/tests/test_core/generic/test_node.py +106 -0
  203. lionagi/tests/test_core/generic/test_tree_node.py +73 -0
  204. lionagi/tests/test_core/test_branch.py +115 -292
  205. lionagi/tests/test_core/test_form.py +46 -0
  206. lionagi/tests/test_core/test_report.py +105 -0
  207. lionagi/tests/test_core/test_validator.py +111 -0
  208. lionagi/version.py +1 -1
  209. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/LICENSE +12 -11
  210. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/METADATA +19 -118
  211. lionagi-0.2.1.dist-info/RECORD +240 -0
  212. lionagi/core/branch/__init__.py +0 -4
  213. lionagi/core/branch/base_branch.py +0 -654
  214. lionagi/core/branch/branch.py +0 -471
  215. lionagi/core/branch/branch_flow_mixin.py +0 -96
  216. lionagi/core/branch/executable_branch.py +0 -347
  217. lionagi/core/branch/util.py +0 -323
  218. lionagi/core/direct/__init__.py +0 -6
  219. lionagi/core/direct/predict.py +0 -161
  220. lionagi/core/direct/score.py +0 -278
  221. lionagi/core/direct/select.py +0 -169
  222. lionagi/core/direct/utils.py +0 -87
  223. lionagi/core/direct/vote.py +0 -64
  224. lionagi/core/flow/base/baseflow.py +0 -23
  225. lionagi/core/flow/monoflow/ReAct.py +0 -238
  226. lionagi/core/flow/monoflow/__init__.py +0 -9
  227. lionagi/core/flow/monoflow/chat.py +0 -95
  228. lionagi/core/flow/monoflow/chat_mixin.py +0 -263
  229. lionagi/core/flow/monoflow/followup.py +0 -214
  230. lionagi/core/flow/polyflow/__init__.py +0 -1
  231. lionagi/core/flow/polyflow/chat.py +0 -248
  232. lionagi/core/mail/schema.py +0 -56
  233. lionagi/core/messages/__init__.py +0 -3
  234. lionagi/core/messages/schema.py +0 -533
  235. lionagi/core/prompt/prompt_template.py +0 -316
  236. lionagi/core/schema/__init__.py +0 -22
  237. lionagi/core/schema/action_node.py +0 -29
  238. lionagi/core/schema/base_mixin.py +0 -296
  239. lionagi/core/schema/base_node.py +0 -199
  240. lionagi/core/schema/condition.py +0 -24
  241. lionagi/core/schema/data_logger.py +0 -354
  242. lionagi/core/schema/data_node.py +0 -93
  243. lionagi/core/schema/prompt_template.py +0 -67
  244. lionagi/core/schema/structure.py +0 -910
  245. lionagi/core/tool/__init__.py +0 -3
  246. lionagi/core/tool/tool_manager.py +0 -280
  247. lionagi/integrations/bridge/pydantic_/base_model.py +0 -7
  248. lionagi/tests/test_core/test_base_branch.py +0 -427
  249. lionagi/tests/test_core/test_chat_flow.py +0 -63
  250. lionagi/tests/test_core/test_mail_manager.py +0 -75
  251. lionagi/tests/test_core/test_prompts.py +0 -51
  252. lionagi/tests/test_core/test_session.py +0 -254
  253. lionagi/tests/test_core/test_session_base_util.py +0 -312
  254. lionagi/tests/test_core/test_tool_manager.py +0 -95
  255. lionagi-0.0.312.dist-info/RECORD +0 -111
  256. /lionagi/core/{branch/base → _setting}/__init__.py +0 -0
  257. /lionagi/core/{flow → agent/eval}/__init__.py +0 -0
  258. /lionagi/core/{flow/base → agent/learn}/__init__.py +0 -0
  259. /lionagi/core/{prompt → agent/plan}/__init__.py +0 -0
  260. /lionagi/core/{tool/manual.py → agent/plan/plan.py} +0 -0
  261. /lionagi/{tests/test_integrations → core/director}/__init__.py +0 -0
  262. /lionagi/{tests/test_libs → core/engine}/__init__.py +0 -0
  263. /lionagi/{tests/test_libs/test_async.py → core/executor/__init__.py} +0 -0
  264. /lionagi/tests/{test_libs → libs}/test_api.py +0 -0
  265. /lionagi/tests/{test_libs → libs}/test_convert.py +0 -0
  266. /lionagi/tests/{test_libs → libs}/test_sys_util.py +0 -0
  267. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/WHEEL +0 -0
  268. {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/top_level.txt +0 -0
@@ -1,347 +0,0 @@
1
- """
2
- This module contains the ExecutableBranch class, which represents an executable branch in a conversation tree.
3
- """
4
-
5
- import contextlib
6
- from collections import deque
7
- from typing import Any
8
-
9
- from lionagi.libs import convert, AsyncUtil, ParseUtil
10
-
11
- from ..schema import BaseRelatableNode, ActionNode
12
- from ..mail import BaseMail
13
- from ..messages import System, Instruction
14
- from ..agent import BaseAgent
15
-
16
- from .branch import Branch
17
-
18
-
19
- class ExecutableBranch(BaseRelatableNode):
20
- """
21
- Represents an executable branch in a conversation tree.
22
-
23
- Attributes:
24
- branch (Branch): The branch associated with the executable branch.
25
- pending_ins (dict): The pending incoming mails for the executable branch.
26
- pending_outs (deque): The pending outgoing mails for the executable branch.
27
- responses (list): The responses generated by the executable branch.
28
- execute_stop (bool): A flag indicating whether the execution should stop.
29
- context (Any): The context of the executable branch.
30
- context_log (list): The log of contexts for the executable branch.
31
- verbose (bool): A flag indicating whether to provide verbose output.
32
-
33
- Methods:
34
- __init__(self, verbose=True, **kwargs) -> None:
35
- Initializes the ExecutableBranch instance.
36
-
37
- send(self, recipient_id: str, category: str, package: Any) -> None:
38
- Sends a mail to a recipient.
39
-
40
- async forward(self) -> None:
41
- Forwards the pending incoming mails to the appropriate processing methods.
42
-
43
- async execute(self, refresh_time=1) -> None:
44
- Executes the executable branch.
45
-
46
- async _process_node(self, mail: BaseMail) -> None:
47
- Processes a node mail.
48
-
49
- _process_node_list(self, mail: BaseMail) -> None:
50
- Processes a node list mail.
51
-
52
- _process_condition(self, mail: BaseMail) -> None:
53
- Processes a condition mail.
54
-
55
- _system_process(self, system: System, verbose=True, context_verbose=False) -> None:
56
- Processes a system message.
57
-
58
- async _instruction_process(self, instruction: Instruction, verbose=True, **kwargs) -> None:
59
- Processes an instruction message.
60
-
61
- async _action_process(self, action: ActionNode, verbose=True) -> None:
62
- Processes an action node.
63
-
64
- async _agent_process(self, agent, verbose=True) -> None:
65
- Processes an agent.
66
-
67
- _process_start(self, mail: BaseMail) -> None:
68
- Processes a start mail.
69
-
70
- _process_end(self, mail: BaseMail) -> None:
71
- Processes an end mail.
72
- """
73
-
74
- def __init__(self, verbose=True, **kwargs):
75
- """
76
- Initializes the ExecutableBranch instance.
77
-
78
- Args:
79
- verbose (bool): A flag indicating whether to provide verbose output (default: True).
80
- **kwargs: Additional keyword arguments for initializing the branch.
81
- """
82
- super().__init__()
83
- self.branch: Branch = Branch(**kwargs)
84
- self.pending_ins = {} # needed
85
- self.pending_outs = deque() # needed
86
- self.responses = []
87
- self.execute_stop = False # needed
88
- self.context = None # needed
89
- self.context_log = []
90
- self.verbose = verbose
91
-
92
- def send(self, recipient_id: str, category: str, package: Any) -> None:
93
- """
94
- Sends a mail to a recipient.
95
-
96
- Args:
97
- recipient_id (str): The ID of the recipient.
98
- category (str): The category of the mail.
99
- package (Any): The package to send in the mail.
100
- """
101
- mail = BaseMail(
102
- sender_id=self.id_,
103
- recipient_id=recipient_id,
104
- category=category,
105
- package=package,
106
- )
107
- self.pending_outs.append(mail)
108
-
109
- async def forward(self) -> None:
110
- """
111
- Forwards the pending incoming mails to the appropriate processing methods.
112
- """
113
- for key in list(self.pending_ins.keys()):
114
- while self.pending_ins[key]:
115
- mail = self.pending_ins[key].popleft()
116
- if mail.category == "start":
117
- self._process_start(mail)
118
- elif mail.category == "node":
119
- await self._process_node(mail)
120
- elif mail.category == "node_list":
121
- self._process_node_list(mail)
122
- elif mail.category == "condition":
123
- self._process_condition(mail)
124
- elif mail.category == "end":
125
- self._process_end(mail)
126
-
127
- async def execute(self, refresh_time=1) -> None:
128
- """
129
- Executes the executable branch.
130
-
131
- Args:
132
- refresh_time (int): The refresh time for execution (default: 1).
133
- """
134
- while not self.execute_stop:
135
- await self.forward()
136
- await AsyncUtil.sleep(refresh_time)
137
-
138
- async def _process_node(self, mail: BaseMail):
139
- """
140
- Processes a node mail.
141
-
142
- Args:
143
- mail (BaseMail): The node mail to process.
144
-
145
- Raises:
146
- ValueError: If the mail package is invalid.
147
- """
148
- if isinstance(mail.package, System):
149
- self._system_process(mail.package, verbose=self.verbose)
150
- self.send(mail.sender_id, "node_id", mail.package.id_)
151
-
152
- elif isinstance(mail.package, Instruction):
153
- await self._instruction_process(mail.package, verbose=self.verbose)
154
- self.send(mail.sender_id, "node_id", mail.package.id_)
155
-
156
- elif isinstance(mail.package, ActionNode):
157
- await self._action_process(mail.package, verbose=self.verbose)
158
- self.send(mail.sender_id, "node_id", mail.package.instruction.id_)
159
- else:
160
- try:
161
- await self._agent_process(mail.package, verbose=self.verbose)
162
- self.send(mail.sender_id, "node_id", mail.package.id_)
163
- except:
164
- raise ValueError(f"Invalid mail to process. Mail:{mail}")
165
-
166
- def _process_node_list(self, mail: BaseMail):
167
- """
168
- Processes a node list mail.
169
-
170
- Args:
171
- mail (BaseMail): The node list mail to process.
172
-
173
- Raises:
174
- ValueError: If multiple path selection is not supported.
175
- """
176
- self.send(mail.sender_id, "end", "end")
177
- self.execute_stop = True
178
- raise ValueError("Multiple path selection is currently not supported")
179
-
180
- def _process_condition(self, mail: BaseMail):
181
- """
182
- Processes a condition mail.
183
-
184
- Args:
185
- mail (BaseMail): The condition mail to process.
186
- """
187
- relationship = mail.package
188
- check_result = relationship.condition(self)
189
- back_mail = {"relationship_id": mail.package.id_, "check_result": check_result}
190
- self.send(mail.sender_id, "condition", back_mail)
191
-
192
- def _system_process(self, system: System, verbose=True, context_verbose=False):
193
- """
194
- Processes a system message.
195
-
196
- Args:
197
- system (System): The system message to process.
198
- verbose (bool): A flag indicating whether to provide verbose output (default: True).
199
- context_verbose (bool): A flag indicating whether to display the context (default: False).
200
- """
201
- from lionagi.libs import SysUtil
202
-
203
- SysUtil.check_import("IPython")
204
- from IPython.display import Markdown, display
205
-
206
- if verbose:
207
- print(f"------------------Welcome: {system.sender}--------------------")
208
- display(Markdown(f"system: {convert.to_str(system.system_info)}"))
209
- if self.context and context_verbose:
210
- display(Markdown(f"context: {convert.to_str(self.context)}"))
211
-
212
- self.branch.add_message(system=system)
213
-
214
- async def _instruction_process(
215
- self, instruction: Instruction, verbose=True, **kwargs
216
- ):
217
- """
218
- Processes an instruction message.
219
-
220
- Args:
221
- instruction (Instruction): The instruction message to process.
222
- verbose (bool): A flag indicating whether to provide verbose output (default: True).
223
- **kwargs: Additional keyword arguments for processing the instruction.
224
- """
225
- from lionagi.libs import SysUtil
226
-
227
- SysUtil.check_import("IPython")
228
- from IPython.display import Markdown, display
229
-
230
- if verbose:
231
- display(
232
- Markdown(
233
- f"{instruction.sender}: {convert.to_str(instruction.instruct)}"
234
- )
235
- )
236
-
237
- if self.context:
238
- instruction.content.update({"context": self.context})
239
- self.context = None
240
-
241
- result = await self.branch.chat(instruction, **kwargs)
242
- with contextlib.suppress(Exception):
243
- result = ParseUtil.fuzzy_parse_json(result)
244
- if "response" in result.keys():
245
- result = result["response"]
246
- if verbose and len(self.branch.assistant_responses) != 0:
247
- display(
248
- Markdown(
249
- f"{self.branch.last_assistant_response.sender}: {convert.to_str(result)}"
250
- )
251
- )
252
- print("-----------------------------------------------------")
253
-
254
- self.responses.append(result)
255
-
256
- async def _action_process(self, action: ActionNode, verbose=True):
257
- """
258
- Processes an action node.
259
-
260
- Args:
261
- action (ActionNode): The action node to process.
262
- verbose (bool): A flag indicating whether to provide verbose output (default: True).
263
-
264
- Raises:
265
- ValueError: If the action is not valid.
266
- """
267
- from lionagi.libs import SysUtil
268
-
269
- SysUtil.check_import("IPython")
270
- from IPython.display import Markdown, display
271
-
272
- try:
273
- func = getattr(self.branch, action.action)
274
- except:
275
- raise ValueError(f"{action.action} is not a valid action")
276
-
277
- if verbose:
278
- display(
279
- Markdown(
280
- f"{action.instruction.sender}: {convert.to_str(action.instruction.instruct)}"
281
- )
282
- )
283
-
284
- if action.tools:
285
- self.branch.register_tools(action.tools)
286
- if self.context:
287
- result = await func(
288
- action.instruction.content["instruction"],
289
- context=self.context,
290
- tools=action.tools,
291
- **action.action_kwargs,
292
- )
293
- self.context = None
294
- else:
295
- result = await func(
296
- action.instruction.content, tools=action.tools, **action.action_kwargs
297
- )
298
-
299
- if verbose and len(self.branch.assistant_responses) != 0:
300
- display(
301
- Markdown(
302
- f"{self.branch.last_assistant_response.sender}: {convert.to_str(result)}"
303
- )
304
- )
305
- print("-----------------------------------------------------")
306
-
307
- self.responses.append(result)
308
-
309
- async def _agent_process(self, agent, verbose=True):
310
- """
311
- Processes an agent.
312
-
313
- Args:
314
- agent: The agent to process.
315
- verbose (bool): A flag indicating whether to provide verbose output (default: True).
316
- """
317
- context = self.responses
318
- if verbose:
319
- print("*****************************************************")
320
- result = await agent.execute(context)
321
-
322
- if verbose:
323
- print("*****************************************************")
324
-
325
- self.context = result
326
- self.responses.append(result)
327
-
328
- def _process_start(self, mail):
329
- """
330
- Processes a start mail.
331
-
332
- Args:
333
- mail (BaseMail): The start mail to process.
334
- """
335
- start_mail_content = mail.package
336
- self.context = start_mail_content["context"]
337
- self.send(start_mail_content["structure_id"], "start", "start")
338
-
339
- def _process_end(self, mail):
340
- """
341
- Processes an end mail.
342
-
343
- Args:
344
- mail (BaseMail): The end mail to process.
345
- """
346
- self.execute_stop = True
347
- self.send(mail.sender_id, "end", "end")
@@ -1,323 +0,0 @@
1
- import contextlib
2
- from datetime import datetime
3
- from typing import Any
4
-
5
- from lionagi.libs import convert, nested, func_call, dataframe
6
-
7
- from lionagi.core.messages.schema import (
8
- System,
9
- Instruction,
10
- Response,
11
- BaseMessage,
12
- BranchColumns,
13
- )
14
-
15
- CUSTOM_TYPE = dict[str, Any] | str | list[Any] | None
16
-
17
-
18
- class MessageUtil:
19
-
20
- @staticmethod
21
- def create_message(
22
- system: System | CUSTOM_TYPE = None,
23
- instruction: Instruction | CUSTOM_TYPE = None,
24
- context: str | dict[str, Any] | None = None,
25
- response: Response | CUSTOM_TYPE = None,
26
- output_fields=None,
27
- **kwargs,
28
- ) -> BaseMessage:
29
- """
30
- Creates a message object based on the input parameters, ensuring only one message role is present.
31
-
32
- Args:
33
- system: Information for creating a System message.
34
- instruction: Information for creating an Instruction message.
35
- context: Context information for the message.
36
- response: Response data for creating a message.
37
- **kwargs: Additional keyword arguments for message creation.
38
-
39
- Returns:
40
- A message object of the appropriate type based on provided inputs.
41
-
42
- Raises:
43
- ValueError: If more than one of the role-specific parameters are provided.
44
- """
45
- if sum(func_call.lcall([system, instruction, response], bool)) != 1:
46
- raise ValueError("Error: Message must have one and only one role.")
47
-
48
- if isinstance(system, System):
49
- return system
50
- elif isinstance(instruction, Instruction):
51
- return instruction
52
- elif isinstance(response, Response):
53
- return response
54
-
55
- msg = 0
56
- if response:
57
- msg = Response(response=response, **kwargs)
58
- elif instruction:
59
- msg = Instruction(
60
- instruction=instruction,
61
- context=context,
62
- output_fields=output_fields,
63
- **kwargs,
64
- )
65
- elif system:
66
- msg = System(system=system, **kwargs)
67
- return msg
68
-
69
- @staticmethod
70
- def validate_messages(messages: dataframe.ln_DataFrame) -> bool:
71
- """
72
- Validates the format and content of a DataFrame containing messages.
73
-
74
- Args:
75
- messages: A DataFrame with message information.
76
-
77
- Returns:
78
- True if the messages DataFrame is correctly formatted, False otherwise.
79
-
80
- Raises:
81
- ValueError: If the DataFrame does not match expected schema or content requirements.
82
- """
83
-
84
- if list(messages.columns) != BranchColumns.COLUMNS.value:
85
- raise ValueError("Invalid messages dataframe. Unmatched columns.")
86
- if messages.isnull().values.any():
87
- raise ValueError("Invalid messages dataframe. Cannot have null.")
88
- if any(
89
- role not in ["system", "user", "assistant"]
90
- for role in messages["role"].unique()
91
- ):
92
- raise ValueError(
93
- 'Invalid messages dataframe. Cannot have role other than ["system", "user", "assistant"].'
94
- )
95
- for cont in messages["content"]:
96
- if cont.startswith("Sender"):
97
- cont = cont.split(":", 1)[1]
98
- try:
99
- convert.to_dict(cont)
100
- except:
101
- raise ValueError(
102
- "Invalid messages dataframe. Content expect json string."
103
- )
104
- return True
105
-
106
- @staticmethod
107
- def sign_message(
108
- messages: dataframe.ln_DataFrame, sender: str
109
- ) -> dataframe.ln_DataFrame:
110
- """
111
- Appends a sender prefix to the 'content' field of each message in a DataFrame.
112
-
113
- Args:
114
- messages: A DataFrame containing message data.
115
- sender: The identifier of the sender to prefix to message contents.
116
-
117
- Returns:
118
- A DataFrame with sender-prefixed message contents.
119
-
120
- Raises:
121
- ValueError: If the sender is None or the value is 'none'.
122
- """
123
-
124
- if sender is None or convert.strip_lower(sender) == "none":
125
- raise ValueError("sender cannot be None")
126
- df = convert.to_df(messages)
127
-
128
- for i in df.index:
129
- if not df.loc[i, "content"].startswith("Sender"):
130
- df.loc[i, "content"] = f"Sender {sender}: {df.loc[i, 'content']}"
131
- else:
132
- content = df.loc[i, "content"].split(":", 1)[1]
133
- df.loc[i, "content"] = f"Sender {sender}: {content}"
134
-
135
- return convert.to_df(df)
136
-
137
- @staticmethod
138
- def filter_messages_by(
139
- messages: dataframe.ln_DataFrame,
140
- role: str | None = None,
141
- sender: str | None = None,
142
- start_time: datetime | None = None,
143
- end_time: datetime | None = None,
144
- content_keywords: str | list[str] | None = None,
145
- case_sensitive: bool = False,
146
- ) -> dataframe.ln_DataFrame:
147
- """
148
- Filters messages in a DataFrame based on specified criteria.
149
-
150
- Args:
151
- messages: The DataFrame to filter.
152
- role: The role to filter by.
153
- sender: The sender to filter by.
154
- start_time: The minimum timestamp for messages.
155
- end_time: The maximum timestamp for messages.
156
- content_keywords: Keywords to look for in message content.
157
- case_sensitive: Whether the keyword search should be case-sensitive.
158
-
159
- Returns:
160
- A filtered DataFrame based on the specified criteria.
161
- """
162
-
163
- try:
164
- outs = messages.copy()
165
-
166
- if content_keywords:
167
- outs = MessageUtil.search_keywords(
168
- outs, keywords=content_keywords, case_sensitive=case_sensitive
169
- )
170
-
171
- outs = outs[outs["role"] == role] if role else outs
172
- outs = outs[outs["sender"] == sender] if sender else outs
173
- outs = outs[outs["timestamp"] > start_time] if start_time else outs
174
- outs = outs[outs["timestamp"] < end_time] if end_time else outs
175
-
176
- return convert.to_df(outs)
177
-
178
- except Exception as e:
179
- raise ValueError(f"Error in filtering messages: {e}") from e
180
-
181
- @staticmethod
182
- def remove_message(messages: dataframe.ln_DataFrame, node_id: str) -> bool:
183
- """
184
- Removes a message from the DataFrame based on its node ID.
185
-
186
- Args:
187
- messages: The DataFrame containing messages.
188
- node_id: The unique identifier of the message to be removed.
189
-
190
- Returns:
191
- If any messages are removed.
192
-
193
- Examples:
194
- >>> messages = dataframe.ln_DataFrame([...])
195
- >>> updated_messages = MessageUtil.remove_message(messages, "node_id_123")
196
- """
197
-
198
- initial_length = len(messages)
199
- messages.drop(messages[messages["node_id"] == node_id].index, inplace=True)
200
- messages.reset_index(drop=True, inplace=True)
201
-
202
- return len(messages) < initial_length
203
-
204
- @staticmethod
205
- def get_message_rows(
206
- messages: dataframe.ln_DataFrame,
207
- sender: str | None = None,
208
- role: str | None = None,
209
- n: int = 1,
210
- sign_: bool = False,
211
- from_: str = "front",
212
- ) -> dataframe.ln_DataFrame:
213
- """
214
- Retrieves a specified number of message rows based on sender and role.
215
-
216
- Args:
217
- messages: The DataFrame containing messages.
218
- sender: Filter messages by the sender.
219
- role: Filter messages by the role.
220
- n: The number of messages to retrieve.
221
- sign_: If True, sign the message with the sender.
222
- from_: Specify retrieval from the 'front' or 'last' of the DataFrame.
223
-
224
- Returns:
225
- A DataFrame containing the filtered messages.
226
- """
227
-
228
- outs = ""
229
-
230
- if from_ == "last":
231
- if sender is None and role is None:
232
- outs = messages.iloc[-n:]
233
- elif sender and role:
234
- outs = messages[
235
- (messages["sender"] == sender) & (messages["role"] == role)
236
- ].iloc[-n:]
237
-
238
- elif sender:
239
- outs = messages[messages["sender"] == sender].iloc[-n:]
240
- else:
241
- outs = messages[messages["role"] == role].iloc[-n:]
242
-
243
- elif from_ == "front":
244
- if sender is None and role is None:
245
- outs = messages.iloc[:n]
246
- elif sender and role:
247
- outs = messages[
248
- (messages["sender"] == sender) & (messages["role"] == role)
249
- ].iloc[:n]
250
- elif sender:
251
- outs = messages[messages["sender"] == sender].iloc[:n]
252
- else:
253
- outs = messages[messages["role"] == role].iloc[:n]
254
-
255
- return MessageUtil.sign_message(outs, sender) if sign_ else outs
256
-
257
- @staticmethod
258
- def extend(
259
- df1: dataframe.ln_DataFrame, df2: dataframe.ln_DataFrame, **kwargs
260
- ) -> dataframe.ln_DataFrame:
261
- """
262
- Extends a DataFrame with another DataFrame's rows, ensuring no duplicate 'node_id'.
263
-
264
- Args:
265
- df1: The primary DataFrame.
266
- df2: The DataFrame to merge with the primary DataFrame.
267
- **kwargs: Additional keyword arguments for `drop_duplicates`.
268
-
269
- Returns:
270
- A DataFrame combined from df1 and df2 with duplicates removed based on 'node_id'.
271
-
272
- Examples:
273
- >>> df_main = dataframe.ln_DataFrame([...])
274
- >>> df_additional = dataframe.ln_DataFrame([...])
275
- >>> combined_df = MessageUtil.extend(df_main, df_additional, keep='first')
276
- """
277
-
278
- MessageUtil.validate_messages(df2)
279
- try:
280
- if len(df2.dropna(how="all")) > 0 and len(df1.dropna(how="all")) > 0:
281
- df = convert.to_df([df1, df2])
282
- df.drop_duplicates(
283
- inplace=True, subset=["node_id"], keep="first", **kwargs
284
- )
285
- return convert.to_df(df)
286
- except Exception as e:
287
- raise ValueError(f"Error in extending messages: {e}") from e
288
-
289
- @staticmethod
290
- def to_markdown_string(messages: dataframe.ln_DataFrame) -> str:
291
- """
292
- Converts messages in a DataFrame to a Markdown-formatted string for easy reading.
293
-
294
- Args:
295
- messages: A DataFrame containing messages with columns for 'role' and 'content'.
296
-
297
- Returns:
298
- A string formatted in Markdown, where each message's content is presented
299
- according to its role in a readable format.
300
- """
301
-
302
- answers = []
303
- for _, i in messages.iterrows():
304
- content = convert.to_dict(i.content)
305
-
306
- if i.role == "assistant":
307
- with contextlib.suppress(Exception):
308
- a = nested.nget(content, ["action_response", "func"])
309
- b = nested.nget(content, ["action_response", "arguments"])
310
- c = nested.nget(content, ["action_response", "output"])
311
- if a is not None:
312
- answers.extend(
313
- (f"Function: {a}", f"Arguments: {b}", f"Output: {c}")
314
- )
315
- else:
316
- answers.append(nested.nget(content, ["assistant_response"]))
317
- elif i.role == "user":
318
- with contextlib.suppress(Exception):
319
- answers.append(nested.nget(content, ["instruction"]))
320
- else:
321
- with contextlib.suppress(Exception):
322
- answers.append(nested.nget(content, ["system_info"]))
323
- return "\n".join(answers)
@@ -1,6 +0,0 @@
1
- from .predict import predict
2
- from .select import select
3
- from .score import score
4
- from .vote import vote
5
-
6
- __all__ = ["predict", "select", "score", "vote"]