lionagi 0.1.1__py3-none-any.whl → 0.2.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (257) 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} +83 -67
  35. lionagi/core/{execute → executor}/neo4j_executor.py +70 -67
  36. lionagi/core/generic/__init__.py +3 -33
  37. lionagi/core/generic/edge.py +42 -92
  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/__init__.py +0 -0
  109. lionagi/experimental/knowledge/base.py +10 -0
  110. lionagi/experimental/knowledge/graph.py +0 -0
  111. lionagi/experimental/memory/__init__.py +0 -0
  112. lionagi/experimental/strategies/__init__.py +0 -0
  113. lionagi/experimental/strategies/base.py +1 -0
  114. lionagi/integrations/bridge/langchain_/documents.py +4 -0
  115. lionagi/integrations/bridge/llamaindex_/index.py +30 -0
  116. lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
  117. lionagi/integrations/chunker/chunk.py +161 -24
  118. lionagi/integrations/config/oai_configs.py +34 -3
  119. lionagi/integrations/config/openrouter_configs.py +14 -2
  120. lionagi/integrations/loader/load.py +122 -21
  121. lionagi/integrations/loader/load_util.py +6 -77
  122. lionagi/integrations/provider/_mapping.py +46 -0
  123. lionagi/integrations/provider/litellm.py +2 -1
  124. lionagi/integrations/provider/mlx_service.py +16 -9
  125. lionagi/integrations/provider/oai.py +91 -4
  126. lionagi/integrations/provider/ollama.py +6 -5
  127. lionagi/integrations/provider/openrouter.py +115 -8
  128. lionagi/integrations/provider/services.py +2 -2
  129. lionagi/integrations/provider/transformers.py +18 -22
  130. lionagi/integrations/storage/__init__.py +3 -3
  131. lionagi/integrations/storage/neo4j.py +52 -60
  132. lionagi/integrations/storage/storage_util.py +45 -47
  133. lionagi/integrations/storage/structure_excel.py +285 -0
  134. lionagi/integrations/storage/to_excel.py +23 -7
  135. lionagi/libs/__init__.py +26 -1
  136. lionagi/libs/ln_api.py +75 -20
  137. lionagi/libs/ln_context.py +37 -0
  138. lionagi/libs/ln_convert.py +21 -9
  139. lionagi/libs/ln_func_call.py +69 -28
  140. lionagi/libs/ln_image.py +107 -0
  141. lionagi/libs/ln_nested.py +26 -11
  142. lionagi/libs/ln_parse.py +82 -23
  143. lionagi/libs/ln_queue.py +16 -0
  144. lionagi/libs/ln_tokenize.py +164 -0
  145. lionagi/libs/ln_validate.py +16 -0
  146. lionagi/libs/special_tokens.py +172 -0
  147. lionagi/libs/sys_util.py +95 -24
  148. lionagi/lions/coder/code_form.py +13 -0
  149. lionagi/lions/coder/coder.py +50 -3
  150. lionagi/lions/coder/util.py +30 -25
  151. lionagi/tests/libs/test_func_call.py +23 -21
  152. lionagi/tests/libs/test_nested.py +36 -21
  153. lionagi/tests/libs/test_parse.py +1 -1
  154. lionagi/tests/test_core/collections/__init__.py +0 -0
  155. lionagi/tests/test_core/collections/test_component.py +206 -0
  156. lionagi/tests/test_core/collections/test_exchange.py +138 -0
  157. lionagi/tests/test_core/collections/test_flow.py +145 -0
  158. lionagi/tests/test_core/collections/test_pile.py +171 -0
  159. lionagi/tests/test_core/collections/test_progression.py +129 -0
  160. lionagi/tests/test_core/generic/__init__.py +0 -0
  161. lionagi/tests/test_core/generic/test_edge.py +67 -0
  162. lionagi/tests/test_core/generic/test_graph.py +96 -0
  163. lionagi/tests/test_core/generic/test_node.py +106 -0
  164. lionagi/tests/test_core/generic/test_tree_node.py +73 -0
  165. lionagi/tests/test_core/test_branch.py +115 -294
  166. lionagi/tests/test_core/test_form.py +46 -0
  167. lionagi/tests/test_core/test_report.py +105 -0
  168. lionagi/tests/test_core/test_validator.py +111 -0
  169. lionagi/version.py +1 -1
  170. lionagi-0.2.0.dist-info/LICENSE +202 -0
  171. lionagi-0.2.0.dist-info/METADATA +272 -0
  172. lionagi-0.2.0.dist-info/RECORD +240 -0
  173. lionagi/core/branch/base.py +0 -653
  174. lionagi/core/branch/branch.py +0 -474
  175. lionagi/core/branch/flow_mixin.py +0 -96
  176. lionagi/core/branch/util.py +0 -323
  177. lionagi/core/direct/__init__.py +0 -19
  178. lionagi/core/direct/cot.py +0 -123
  179. lionagi/core/direct/plan.py +0 -164
  180. lionagi/core/direct/predict.py +0 -166
  181. lionagi/core/direct/react.py +0 -171
  182. lionagi/core/direct/score.py +0 -279
  183. lionagi/core/direct/select.py +0 -170
  184. lionagi/core/direct/sentiment.py +0 -1
  185. lionagi/core/direct/utils.py +0 -110
  186. lionagi/core/direct/vote.py +0 -64
  187. lionagi/core/execute/base_executor.py +0 -47
  188. lionagi/core/flow/baseflow.py +0 -23
  189. lionagi/core/flow/monoflow/ReAct.py +0 -238
  190. lionagi/core/flow/monoflow/__init__.py +0 -9
  191. lionagi/core/flow/monoflow/chat.py +0 -95
  192. lionagi/core/flow/monoflow/chat_mixin.py +0 -253
  193. lionagi/core/flow/monoflow/followup.py +0 -213
  194. lionagi/core/flow/polyflow/__init__.py +0 -1
  195. lionagi/core/flow/polyflow/chat.py +0 -251
  196. lionagi/core/form/action_form.py +0 -26
  197. lionagi/core/form/field_validator.py +0 -287
  198. lionagi/core/form/form.py +0 -302
  199. lionagi/core/form/mixin.py +0 -214
  200. lionagi/core/form/scored_form.py +0 -13
  201. lionagi/core/generic/action.py +0 -26
  202. lionagi/core/generic/component.py +0 -455
  203. lionagi/core/generic/condition.py +0 -44
  204. lionagi/core/generic/mail.py +0 -90
  205. lionagi/core/generic/mailbox.py +0 -36
  206. lionagi/core/generic/relation.py +0 -70
  207. lionagi/core/generic/signal.py +0 -22
  208. lionagi/core/generic/structure.py +0 -362
  209. lionagi/core/generic/transfer.py +0 -20
  210. lionagi/core/generic/work.py +0 -40
  211. lionagi/core/graph/graph.py +0 -126
  212. lionagi/core/graph/tree.py +0 -190
  213. lionagi/core/mail/schema.py +0 -63
  214. lionagi/core/messages/schema.py +0 -325
  215. lionagi/core/tool/__init__.py +0 -5
  216. lionagi/core/tool/tool.py +0 -28
  217. lionagi/core/tool/tool_manager.py +0 -282
  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/work/_logger.py +0 -25
  224. lionagi/experimental/work/schema.py +0 -30
  225. lionagi/experimental/work/tests.py +0 -72
  226. lionagi/experimental/work/work_function.py +0 -89
  227. lionagi/experimental/work/worker.py +0 -12
  228. lionagi/integrations/bridge/llamaindex_/get_index.py +0 -294
  229. lionagi/tests/test_core/test_base_branch.py +0 -426
  230. lionagi/tests/test_core/test_chat_flow.py +0 -63
  231. lionagi/tests/test_core/test_mail_manager.py +0 -75
  232. lionagi/tests/test_core/test_prompts.py +0 -51
  233. lionagi/tests/test_core/test_session.py +0 -254
  234. lionagi/tests/test_core/test_session_base_util.py +0 -313
  235. lionagi/tests/test_core/test_tool_manager.py +0 -95
  236. lionagi-0.1.1.dist-info/LICENSE +0 -9
  237. lionagi-0.1.1.dist-info/METADATA +0 -174
  238. lionagi-0.1.1.dist-info/RECORD +0 -190
  239. /lionagi/core/{branch → _setting}/__init__.py +0 -0
  240. /lionagi/core/{execute → agent/eval}/__init__.py +0 -0
  241. /lionagi/core/{flow → agent/learn}/__init__.py +0 -0
  242. /lionagi/core/{form → agent/plan}/__init__.py +0 -0
  243. /lionagi/core/{branch/executable_branch.py → agent/plan/plan.py} +0 -0
  244. /lionagi/core/{graph → director}/__init__.py +0 -0
  245. /lionagi/core/{messages → engine}/__init__.py +0 -0
  246. /lionagi/{experimental/directive/evaluator → core/engine}/sandbox_.py +0 -0
  247. /lionagi/{experimental/directive/evaluator → core/executor}/__init__.py +0 -0
  248. /lionagi/{experimental/directive/template_ → core/rule}/__init__.py +0 -0
  249. /lionagi/{experimental/tool → core/unit/template}/__init__.py +0 -0
  250. /lionagi/{experimental/work → core/validator}/__init__.py +0 -0
  251. /lionagi/core/{flow/mono_chat_mixin.py → work/__init__.py} +0 -0
  252. /lionagi/experimental/{work/exchange.py → compressor/__init__.py} +0 -0
  253. /lionagi/experimental/{work/util.py → directive/template/__init__.py} +0 -0
  254. /lionagi/experimental/directive/{schema.py → template/schema.py} +0 -0
  255. /lionagi/{tests/libs/test_async.py → experimental/evaluator/__init__.py} +0 -0
  256. {lionagi-0.1.1.dist-info → lionagi-0.2.0.dist-info}/WHEEL +0 -0
  257. {lionagi-0.1.1.dist-info → lionagi-0.2.0.dist-info}/top_level.txt +0 -0
@@ -1,23 +1,52 @@
1
1
  import contextlib
2
2
  from lionagi.libs import convert, AsyncUtil, ParseUtil
3
- from lionagi.core.generic import ActionNode, Edge
4
- from lionagi.core.mail.schema import BaseMail
5
- from lionagi.core.messages.schema import System, Instruction
3
+ from lionagi.core.generic.edge import Edge
4
+ from lionagi.core.action import ActionNode
5
+ from lionagi.core.mail.mail import Mail
6
+ from lionagi.core.message import System, Instruction
7
+ from lionagi.core.collections import Pile, Progression
6
8
 
7
- from lionagi.core.branch.branch import Branch
8
- from lionagi.core.execute.base_executor import BaseExecutor
9
+ from lionagi.core.session.branch import Branch
10
+ from lionagi.core.executor.base_executor import BaseExecutor
9
11
 
10
12
 
11
13
  class BranchExecutor(Branch, BaseExecutor):
12
14
 
15
+ def __init__(
16
+ self,
17
+ context=None,
18
+ verbose=True,
19
+ system=None,
20
+ user=None,
21
+ messages=None,
22
+ progress=None,
23
+ tool_manager=None,
24
+ tools=None,
25
+ imodel=None,
26
+ **kwargs,
27
+ ):
28
+ super().__init__(
29
+ system=system,
30
+ user=user,
31
+ messages=messages,
32
+ progress=progress,
33
+ tool_manager=tool_manager,
34
+ tools=tools,
35
+ imodel=imodel,
36
+ **kwargs,
37
+ )
38
+ self.context = context
39
+ self.verbose = verbose
40
+
13
41
  async def forward(self) -> None:
14
42
  """
15
43
  Forwards the execution by processing all pending incoming mails in each branch. Depending on the category of the mail,
16
44
  it processes starts, nodes, node lists, conditions, or ends, accordingly executing different functions.
17
45
  """
18
- for key in list(self.pending_ins.keys()):
19
- while self.pending_ins[key]:
20
- mail = self.pending_ins[key].popleft()
46
+ for key in list(self.mailbox.pending_ins.keys()):
47
+ while self.mailbox.pending_ins[key].size() > 0:
48
+ mail_id = self.mailbox.pending_ins[key].popleft()
49
+ mail = self.mailbox.pile.pop(mail_id)
21
50
  if mail.category == "start":
22
51
  self._process_start(mail)
23
52
  elif mail.category == "node":
@@ -25,9 +54,11 @@ class BranchExecutor(Branch, BaseExecutor):
25
54
  elif mail.category == "node_list":
26
55
  self._process_node_list(mail)
27
56
  elif mail.category == "condition":
28
- self._process_condition(mail)
57
+ await self._process_condition(mail)
29
58
  elif mail.category == "end":
30
59
  self._process_end(mail)
60
+ if self.mailbox.pending_ins[key].size() == 0:
61
+ self.mailbox.pending_ins.pop(key)
31
62
 
32
63
  async def execute(self, refresh_time=1) -> None:
33
64
  """
@@ -40,60 +71,57 @@ class BranchExecutor(Branch, BaseExecutor):
40
71
  await self.forward()
41
72
  await AsyncUtil.sleep(refresh_time)
42
73
 
43
- async def _process_node(self, mail: BaseMail):
74
+ async def _process_node(self, mail: Mail):
44
75
  """
45
76
  Processes a single node based on the node type specified in the mail's package. It handles different types of nodes such as System,
46
77
  Instruction, ActionNode, and generic nodes through separate processes.
47
78
 
48
79
  Args:
49
- mail (BaseMail): The mail containing the node to be processed along with associated details.
80
+ mail (Mail): The mail containing the node to be processed along with associated details.
50
81
 
51
82
  Raises:
52
83
  ValueError: If an invalid mail is encountered or the process encounters errors.
53
84
  """
54
- if isinstance(mail.package["package"], System):
55
- self._system_process(mail.package["package"], verbose=self.verbose)
85
+ node = mail.package.package
86
+ if isinstance(node, System):
87
+ self._system_process(node, verbose=self.verbose)
56
88
  self.send(
57
- mail.sender_id,
58
- "node_id",
59
- {"request_source": self.id_, "package": mail.package["package"].id_},
89
+ recipient=mail.sender,
90
+ category="node_id",
91
+ package=node.ln_id,
92
+ request_source=self.ln_id,
60
93
  )
61
94
 
62
- elif isinstance(mail.package["package"], Instruction):
63
- await self._instruction_process(
64
- mail.package["package"], verbose=self.verbose
65
- )
95
+ elif isinstance(node, Instruction):
96
+ await self._instruction_process(node, verbose=self.verbose)
66
97
  self.send(
67
- mail.sender_id,
68
- "node_id",
69
- {"request_source": self.id_, "package": mail.package["package"].id_},
98
+ recipient=mail.sender,
99
+ category="node_id",
100
+ package=node.ln_id,
101
+ request_source=self.ln_id,
70
102
  )
71
103
 
72
- elif isinstance(mail.package["package"], ActionNode):
73
- await self._action_process(mail.package["package"], verbose=self.verbose)
104
+ elif isinstance(node, ActionNode):
105
+ await self._action_process(node, verbose=self.verbose)
74
106
  self.send(
75
- mail.sender_id,
76
- "node_id",
77
- {
78
- "request_source": self.id_,
79
- "package": mail.package["package"].instruction.id_,
80
- },
107
+ recipient=mail.sender,
108
+ category="node_id",
109
+ package=node.instruction.ln_id,
110
+ request_source=self.ln_id,
81
111
  )
82
112
  else:
83
113
  try:
84
- await self._agent_process(mail.package["package"], verbose=self.verbose)
114
+ await self._agent_process(node, verbose=self.verbose)
85
115
  self.send(
86
- mail.sender_id,
87
- "node_id",
88
- {
89
- "request_source": self.id_,
90
- "package": mail.package["package"].id_,
91
- },
116
+ recipient=mail.sender,
117
+ category="node_id",
118
+ package=node.ln_id,
119
+ request_source=self.ln_id,
92
120
  )
93
121
  except:
94
122
  raise ValueError(f"Invalid mail to process. Mail:{mail}")
95
123
 
96
- def _process_node_list(self, mail: BaseMail):
124
+ def _process_node_list(self, mail: Mail):
97
125
  """
98
126
  Processes a list of nodes provided in the mail, but currently only sends an end signal as multiple path selection is not supported.
99
127
 
@@ -103,28 +131,29 @@ class BranchExecutor(Branch, BaseExecutor):
103
131
  Raises:
104
132
  ValueError: When trying to process multiple paths which is currently unsupported.
105
133
  """
106
- self.send(mail.sender_id, "end", {"request_source": self.id_, "package": "end"})
134
+ self.send(mail.sender, category="end", package="end", request_source=self.ln_id)
107
135
  self.execute_stop = True
108
- raise ValueError("Multiple path selection is currently not supported")
136
+ raise ValueError("Multiple path selection is not supported in BranchExecutor")
109
137
 
110
- def _process_condition(self, mail: BaseMail):
138
+ async def _process_condition(self, mail: Mail):
111
139
  """
112
140
  Processes a condition associated with an edge based on the mail's package, setting up the result of the condition check.
113
141
 
114
142
  Args:
115
143
  mail (BaseMail): The mail containing the condition to be processed.
116
144
  """
117
- relationship: Edge = mail.package["package"]
118
- check_result = relationship.condition(self)
145
+ edge: Edge = mail.package.package
146
+ check_result = await edge.check_condition(self)
119
147
  back_mail = {
120
- "from": self.id_,
121
- "edge_id": mail.package["package"].id_,
148
+ "from": self.ln_id,
149
+ "edge_id": edge.ln_id,
122
150
  "check_result": check_result,
123
151
  }
124
152
  self.send(
125
- mail.sender_id,
126
- "condition",
127
- {"request_source": self.id_, "package": back_mail},
153
+ recipient=mail.sender,
154
+ category="condition",
155
+ package=back_mail,
156
+ request_source=self.ln_id,
128
157
  )
129
158
 
130
159
  def _system_process(self, system: System, verbose=True, context_verbose=False):
@@ -177,21 +206,22 @@ class BranchExecutor(Branch, BaseExecutor):
177
206
  )
178
207
 
179
208
  if self.context:
180
- instruction.content.update({"context": self.context})
181
- self.context_log.append(self.context)
209
+ result = await self.chat(
210
+ instruction=instruction.instruct, context=self.context, **kwargs
211
+ )
182
212
  self.context = None
213
+ else:
214
+ result = await self.chat(instruction=instruction.instruct, **kwargs)
215
+ # instruction._add_context(context=self.context)
216
+ # self.context_log.append(self.context)
217
+ # self.context = None
183
218
 
184
- result = await self.chat(instruction, **kwargs)
185
219
  with contextlib.suppress(Exception):
186
220
  result = ParseUtil.fuzzy_parse_json(result)
187
- if "response" in result.keys():
188
- result = result["response"]
189
- if verbose and len(self.assistant_responses) != 0:
190
- display(
191
- Markdown(
192
- f"{self.last_assistant_response.sender}: {convert.to_str(result)}"
193
- )
194
- )
221
+ if "assistant_response" in result.keys():
222
+ result = result["assistant_response"]
223
+ if verbose:
224
+ display(Markdown(f"assistant {self.ln_id}: {convert.to_str(result)}"))
195
225
  print("-----------------------------------------------------")
196
226
 
197
227
  self.execution_responses.append(result)
@@ -209,10 +239,10 @@ class BranchExecutor(Branch, BaseExecutor):
209
239
  SysUtil.check_import("IPython")
210
240
  from IPython.display import Markdown, display
211
241
 
212
- try:
213
- func = getattr(self, action.action)
214
- except:
215
- raise ValueError(f"{action.action} is not a valid action")
242
+ # try:
243
+ # func = getattr(self, action.action)
244
+ # except:
245
+ # raise ValueError(f"{action.action} is not a valid action")
216
246
 
217
247
  if verbose:
218
248
  display(
@@ -221,27 +251,33 @@ class BranchExecutor(Branch, BaseExecutor):
221
251
  )
222
252
  )
223
253
 
224
- if action.tools:
225
- self.register_tools(action.tools)
226
- if self.context:
227
- result = await func(
228
- action.instruction.content["instruction"],
229
- context=self.context,
230
- tools=action.tools,
231
- **action.action_kwargs,
232
- )
233
- self.context = None
234
- else:
235
- result = await func(
236
- action.instruction.content, tools=action.tools, **action.action_kwargs
237
- )
254
+ # if action.tools:
255
+ # self.register_tools(action.tools)
256
+ # if self.context:
257
+ # result = await self.direct(
258
+ # action.directive,
259
+ # instruction=action.instruction.instruct,
260
+ # context=self.context,
261
+ # tools=action.tools,
262
+ # **action.directive_kwargs,
263
+ # )
264
+ result = await action.invoke(branch=self, context=self.context)
265
+ self.context = None
266
+ # else:
267
+ # result = await self.direct(
268
+ # action.directive,
269
+ # instruction=action.instruction.content,
270
+ # tools=action.tools,
271
+ # **action.directive_kwargs
272
+ # )
238
273
 
239
- if verbose and len(self.assistant_responses) != 0:
240
- display(
241
- Markdown(
242
- f"{self.last_assistant_response.sender}: {convert.to_str(result)}"
243
- )
244
- )
274
+ if verbose:
275
+ if action.directive == "chat":
276
+ display(Markdown(f"assistant {self.ln_id}: {convert.to_str(result)}"))
277
+ else:
278
+ display(Markdown(f"assistant {self.ln_id}:\n"))
279
+ for k, v in result.work_fields.items():
280
+ display(Markdown(f"{k}: \n{v}\n"))
245
281
  print("-----------------------------------------------------")
246
282
 
247
283
  self.execution_responses.append(result)
@@ -254,7 +290,7 @@ class BranchExecutor(Branch, BaseExecutor):
254
290
  agent: The agent to process.
255
291
  verbose (bool): A flag indicating whether to provide verbose output (default: True).
256
292
  """
257
- context = list(self.messages["content"])
293
+ context = [msg["content"] for msg in self.to_chat_messages()]
258
294
  if verbose:
259
295
  print("*****************************************************")
260
296
  result = await agent.execute(context)
@@ -262,12 +298,7 @@ class BranchExecutor(Branch, BaseExecutor):
262
298
  if verbose:
263
299
  print("*****************************************************")
264
300
 
265
- from pandas import DataFrame
266
-
267
- if isinstance(result, DataFrame):
268
- self.context = list(result["content"])
269
- else:
270
- self.context = result
301
+ self.context = result
271
302
  self.execution_responses.append(result)
272
303
 
273
304
  def _process_start(self, mail):
@@ -277,15 +308,16 @@ class BranchExecutor(Branch, BaseExecutor):
277
308
  Args:
278
309
  mail (BaseMail): The start mail to process.
279
310
  """
280
- start_mail_content = mail.package
311
+ start_mail_content = mail.package.package
281
312
  self.context = start_mail_content["context"]
282
313
  self.send(
283
- start_mail_content["structure_id"],
284
- "start",
285
- {"request_source": self.id_, "package": "start"},
314
+ recipient=start_mail_content["structure_id"],
315
+ category="start",
316
+ package="start",
317
+ request_source=self.ln_id,
286
318
  )
287
319
 
288
- def _process_end(self, mail: BaseMail):
320
+ def _process_end(self, mail: Mail):
289
321
  """
290
322
  Processes an end mail.
291
323
 
@@ -293,4 +325,9 @@ class BranchExecutor(Branch, BaseExecutor):
293
325
  mail (BaseMail): The end mail to process.
294
326
  """
295
327
  self.execute_stop = True
296
- self.send(mail.sender_id, "end", {"request_source": self.id_, "package": "end"})
328
+ self.send(
329
+ recipient=mail.sender,
330
+ category="end",
331
+ package="end",
332
+ request_source=self.ln_id,
333
+ )
@@ -1,33 +1,33 @@
1
1
  import asyncio
2
2
  from pydantic import Field
3
3
 
4
- from lionagi.libs import AsyncUtil
5
-
6
- from lionagi.core.mail.schema import BaseMail, MailTransfer
4
+ from lionagi.core.mail.mail import Mail, Package
5
+ from lionagi.core.collections import Exchange
7
6
  from lionagi.core.mail.mail_manager import MailManager
8
- from lionagi.core.execute.base_executor import BaseExecutor
9
- from lionagi.core.execute.branch_executor import BranchExecutor
7
+ from lionagi.core.executor.base_executor import BaseExecutor
8
+ from lionagi.core.engine.branch_engine import BranchExecutor
9
+ from lionagi.core.collections import progression, pile, Pile
10
10
 
11
11
 
12
- class InstructionMapExecutor(BaseExecutor):
12
+ class InstructionMapEngine(BaseExecutor):
13
13
  """
14
14
  Manages the execution of a mapped set of instructions across multiple branches within an executable structure.
15
15
 
16
16
  Attributes:
17
17
  branches (dict[str, BranchExecutor]): A dictionary of branch executors managing individual instruction flows.
18
18
  structure_id (str): The identifier for the structure within which these branches operate.
19
- mail_transfer (MailTransfer): Handles the transfer of mail between branches and other components.
19
+ mail_transfer (Exchange): Handles the transfer of mail between branches and other components.
20
20
  branch_kwargs (dict): Keyword arguments used for initializing branches.
21
21
  num_end_branches (int): Tracks the number of branches that have completed execution.
22
22
  mail_manager (MailManager): Manages the distribution and collection of mails across branches.
23
23
  """
24
24
 
25
- branches: dict[str, BranchExecutor] = Field(
25
+ branches: Pile[BranchExecutor] = Field(
26
26
  default_factory=dict, description="The branches of the instruction mapping."
27
27
  )
28
28
  structure_id: str = Field("", description="The ID of the executable structure.")
29
- mail_transfer: MailTransfer = Field(
30
- default_factory=MailTransfer, description="The mail transfer."
29
+ mail_transfer: Exchange = Field(
30
+ default_factory=Exchange, description="The mail transfer."
31
31
  )
32
32
  branch_kwargs: dict = Field(
33
33
  default_factory=dict,
@@ -53,9 +53,10 @@ class InstructionMapExecutor(BaseExecutor):
53
53
  Processes incoming mails, directing them appropriately based on their categories, and handles the initial setup
54
54
  of branches or the routing of node and condition mails.
55
55
  """
56
- for key in list(self.pending_ins.keys()):
57
- while self.pending_ins[key]:
58
- mail: BaseMail = self.pending_ins[key].popleft()
56
+ for key in list(self.mailbox.pending_ins.keys()):
57
+ while self.mailbox.pending_ins[key].size() > 0:
58
+ mail_id = self.mailbox.pending_ins[key].popleft()
59
+ mail = self.mailbox.pile.pop(mail_id)
59
60
  if mail.category == "start":
60
61
  self._process_start(mail)
61
62
  elif mail.category == "node_list":
@@ -65,9 +66,9 @@ class InstructionMapExecutor(BaseExecutor):
65
66
  or (mail.category == "condition")
66
67
  or (mail.category == "end")
67
68
  ):
68
- mail.sender_id = self.mail_transfer.id_
69
- mail.recipient_id = mail.package["request_source"]
70
- self.mail_transfer.pending_outs.append(mail)
69
+ mail.sender = self.mail_transfer.ln_id
70
+ mail.recipient = mail.package.request_source
71
+ self.mail_transfer.include(mail, "out")
71
72
 
72
73
  def transfer_outs(self):
73
74
  """
@@ -75,23 +76,24 @@ class InstructionMapExecutor(BaseExecutor):
75
76
  other mails to appropriate recipients.
76
77
  """
77
78
  for key in list(self.mail_transfer.pending_ins.keys()):
78
- while self.mail_transfer.pending_ins[key]:
79
- mail: BaseMail = self.mail_transfer.pending_ins[key].popleft()
79
+ while self.mail_transfer.pending_ins[key].size() > 0:
80
+ mail_id = self.mail_transfer.pending_ins[key].popleft()
81
+ mail = self.mail_transfer.pile.pop(mail_id)
80
82
  if mail.category == "end":
81
83
  self.num_end_branches += 1
82
84
  if self.num_end_branches == len(
83
85
  self.branches
84
86
  ): # tell when structure should stop
85
- mail.sender_id = self.id_
86
- mail.recipient_id = self.structure_id
87
- self.pending_outs.append(mail)
87
+ mail.sender = self.ln_id
88
+ mail.recipient = self.structure_id
89
+ self.mailbox.include(mail, "out")
88
90
  self.execute_stop = True
89
91
  else:
90
- mail.sender_id = self.id_
91
- mail.recipient_id = self.structure_id
92
- self.pending_outs.append(mail)
92
+ mail.sender = self.ln_id
93
+ mail.recipient = self.structure_id
94
+ self.mailbox.include(mail, "out")
93
95
 
94
- def _process_start(self, start_mail: BaseMail):
96
+ def _process_start(self, start_mail: Mail):
95
97
  """
96
98
  Processes a start mail to initialize a new branch executor and configures it based on the mail's package content.
97
99
 
@@ -99,19 +101,20 @@ class InstructionMapExecutor(BaseExecutor):
99
101
  start_mail (BaseMail): The mail initiating the start of a new branch execution.
100
102
  """
101
103
  branch = BranchExecutor(verbose=self.verbose, **self.branch_kwargs)
102
- branch.context = start_mail.package["context"]
103
- self.branches[branch.id_] = branch
104
+ branch.context = start_mail.package.package["context"]
105
+ self.branches[branch.ln_id] = branch
104
106
  self.mail_manager.add_sources([branch])
105
- self.structure_id = start_mail.package["structure_id"]
106
- mail = BaseMail(
107
- sender_id=self.id_,
108
- recipient_id=self.structure_id,
109
- category="start",
110
- package={"request_source": branch.id_, "package": "start"},
107
+ self.structure_id = start_mail.package.package["structure_id"]
108
+
109
+ pack = Package(category="start", package="start", request_source=branch.ln_id)
110
+ mail = Mail(
111
+ sender=self.ln_id,
112
+ recipient=self.structure_id,
113
+ package=pack,
111
114
  )
112
- self.pending_outs.append(mail)
115
+ self.mailbox.include(mail, "out")
113
116
 
114
- def _process_node_list(self, nl_mail: BaseMail):
117
+ def _process_node_list(self, nl_mail: Mail):
115
118
  """
116
119
  Processes a node list mail, setting up new branches or propagating the execution context based on the node list
117
120
  provided in the mail.
@@ -119,39 +122,59 @@ class InstructionMapExecutor(BaseExecutor):
119
122
  Args:
120
123
  nl_mail (BaseMail): The mail containing a list of nodes to be processed in subsequent branches.
121
124
  """
122
- source_branch_id = nl_mail.package["request_source"]
123
- node_list = nl_mail.package["package"]
125
+ source_branch_id = nl_mail.package.request_source
126
+ node_list = nl_mail.package.package
124
127
  shared_context = self.branches[source_branch_id].context
125
128
  shared_context_log = self.branches[source_branch_id].context_log
126
129
  base_branch = self.branches[source_branch_id]
127
130
 
128
- first_node_mail = BaseMail(
129
- sender_id=self.mail_transfer.id_,
130
- recipient_id=source_branch_id,
131
- category="node",
132
- package={"request_source": source_branch_id, "package": node_list[0]},
131
+ pack = Package(
132
+ category="node", package=node_list[0], request_source=source_branch_id
133
133
  )
134
- self.mail_transfer.pending_outs.append(first_node_mail)
134
+ mail = Mail(
135
+ sender=self.mail_transfer.ln_id,
136
+ recipient=source_branch_id,
137
+ package=pack,
138
+ )
139
+ self.mail_transfer.include(mail, "out")
135
140
 
136
141
  for i in range(1, len(node_list)):
142
+ system = base_branch.system.clone() if base_branch.system else None
143
+ if system:
144
+ system.sender = base_branch.ln_id
145
+ progress = progression()
146
+ messages = pile()
147
+
148
+ for id_ in base_branch.progress:
149
+ clone_message = base_branch.messages[id_].clone()
150
+ progress.append(clone_message.ln_id)
151
+ messages.append(clone_message)
152
+
137
153
  branch = BranchExecutor(
138
154
  verbose=self.verbose,
139
- messages=base_branch.messages.copy(),
140
- service=base_branch.service,
141
- llmconfig=base_branch.llmconfig,
142
- datalogger=base_branch.datalogger,
155
+ messages=messages,
156
+ user=base_branch.user,
157
+ system=base_branch.system.clone(),
158
+ progress=progress,
159
+ imodel=base_branch.imodel,
143
160
  )
161
+ for message in branch.messages:
162
+ message.sender = base_branch.ln_id
163
+ message.recipient = branch.ln_id
164
+
144
165
  branch.context = shared_context
145
166
  branch.context_log = shared_context_log
146
- self.branches[branch.id_] = branch
167
+ self.branches[branch.ln_id] = branch
147
168
  self.mail_manager.add_sources([branch])
148
- node_mail = BaseMail(
149
- sender_id=self.mail_transfer.id_,
150
- recipient_id=branch.id_,
151
- category="node",
152
- package={"request_source": source_branch_id, "package": node_list[i]},
169
+ node_pacakge = Package(
170
+ category="node", package=node_list[i], request_source=source_branch_id
171
+ )
172
+ node_mail = Mail(
173
+ sender=self.mail_transfer.ln_id,
174
+ recipient=branch.ln_id,
175
+ package=node_pacakge,
153
176
  )
154
- self.mail_transfer.pending_outs.append(node_mail)
177
+ self.mail_transfer.include(node_mail, "out")
155
178
 
156
179
  async def forward(self):
157
180
  """
@@ -162,7 +185,9 @@ class InstructionMapExecutor(BaseExecutor):
162
185
  self.mail_manager.collect_all()
163
186
  self.mail_manager.send_all()
164
187
  tasks = [
165
- branch.forward() for branch in self.branches.values() if branch.pending_ins
188
+ branch.forward()
189
+ for branch in self.branches.values()
190
+ if branch.mailbox.pending_ins
166
191
  ]
167
192
  await asyncio.gather(*tasks)
168
193
  return
@@ -1,7 +1,23 @@
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
+
1
17
  import ast
2
18
  from functools import lru_cache
3
19
  from lionagi.libs import AsyncUtil
4
- from .base_evaluator import BaseEvaluator
20
+ from ..evaluator.base_evaluator import BaseEvaluator
5
21
  from .sandbox_ import SandboxTransformer
6
22
 
7
23