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
@@ -1,294 +1,115 @@
1
- # from lionagi.core.branch.branch import Branch
2
- # from lionagi.core.tool.tool_manager import ToolManager, func_to_tool
3
- # from lionagi.core.schema import DataLogger
4
- # from lionagi.core.branch.util import MessageUtil
5
-
6
-
7
- # import unittest
8
- # from unittest.mock import patch, MagicMock
9
- # import pandas as pd
10
- # import json
11
- # from collections import deque
12
-
13
-
14
- # class TestBranch(unittest.TestCase):
15
- # def setUp(self):
16
- # # Assuming no need for actual files or external services for initialization
17
- # self.test_messages = [
18
- # {
19
- # "node_id": "1",
20
- # "timestamp": "2021-01-01 00:00:00",
21
- # "role": "system",
22
- # "sender": "system",
23
- # "content": json.dumps({"system_info": "System message"}),
24
- # },
25
- # {
26
- # "node_id": "2",
27
- # "timestamp": "2021-01-01 00:01:00",
28
- # "role": "user",
29
- # "sender": "user1",
30
- # "content": json.dumps({"instruction": "User message"}),
31
- # },
32
- # {
33
- # "node_id": "3",
34
- # "timestamp": "2021-01-01 00:02:00",
35
- # "role": "assistant",
36
- # "sender": "assistant",
37
- # "content": json.dumps({"response": "Assistant response"}),
38
- # },
39
- # {
40
- # "node_id": "4",
41
- # "timestamp": "2021-01-01 00:03:00",
42
- # "role": "assistant",
43
- # "sender": "action_request",
44
- # "content": json.dumps({"action_request": "Action request"}),
45
- # },
46
- # {
47
- # "node_id": "5",
48
- # "timestamp": "2021-01-01 00:04:00",
49
- # "role": "assistant",
50
- # "sender": "action_response",
51
- # "content": json.dumps({"action_response": "Action response"}),
52
- # },
53
- # ]
54
- # self.branch = Branch(
55
- # branch_name="TestBranch", messages=pd.DataFrame(self.test_messages)
56
- # )
57
-
58
- # def sample_func(param1: int) -> bool:
59
- # """Sample function.
60
-
61
- # Args:
62
- # param1 (int): Description of param1.
63
-
64
- # Returns:
65
- # bool: Description of return value.
66
- # """
67
- # return True
68
-
69
- # self.tool = func_to_tool(sample_func)
70
-
71
- # def test_initialization(self):
72
- # """Test the initialization of the Branch class."""
73
- # self.assertEqual(self.branch.branch_name, "TestBranch")
74
- # self.assertIsInstance(self.branch.tool_manager, ToolManager)
75
- # self.assertIsInstance(self.branch.datalogger, DataLogger)
76
- # self.assertEqual(self.branch.sender, "system")
77
-
78
- # def test_has_tools_property(self):
79
- # """Test the has_tools property."""
80
- # # Initially, no tools are registered
81
- # self.assertFalse(self.branch.has_tools)
82
-
83
- # # Mock tool registration
84
- # self.branch.register_tools(self.tool)
85
- # self.assertTrue(self.branch.has_tools)
86
-
87
-
88
- # # @patch("lionagi.core.branch.BaseBranch._from_csv")
89
- # # def test_from_csv(self, mock_from_csv):
90
- # # """Test creating a Branch instance from a CSV file."""
91
- # # filepath = "path/to/your/csvfile.csv"
92
- # # Branch.from_csv(filepath=filepath, branch_name="TestBranchFromCSV")
93
- # # mock_from_csv.assert_called_once_with(
94
- # # filepath=filepath,
95
- # # read_kwargs=None,
96
- # # branch_name="TestBranchFromCSV",
97
- # # service=None,
98
- # # llmconfig=None,
99
- # # tools=None,
100
- # # datalogger=None,
101
- # # persist_path=None,
102
- # # tool_manager=None,
103
- # # )
104
-
105
- # # @patch("lionagi.core.branch.BaseBranch._from_json")
106
- # # def test_from_json(self, mock_from_json):
107
- # # """Test creating a Branch instance from a JSON file."""
108
- # # filepath = "path/to/your/jsonfile.json"
109
- # # Branch.from_json_string(filepath=filepath, branch_name="TestBranchFromJSON")
110
- # # mock_from_json.assert_called_once_with(
111
- # # filepath=filepath,
112
- # # read_kwargs=None,
113
- # # branch_name="TestBranchFromJSON",
114
- # # service=None,
115
- # # llmconfig=None,
116
- # # tools=None,
117
- # # datalogger=None,
118
- # # persist_path=None,
119
- # # tool_manager=None,
120
- # # )
121
-
122
-
123
- # def test_messages_describe(self):
124
- # """Test the messages_describe method for accuracy."""
125
- # # Assuming self.branch has been set up with some messages
126
- # description = self.branch.messages_describe()
127
- # self.assertIn("total_messages", description)
128
- # self.assertIn("summary_by_role", description)
129
- # self.assertIn("summary_by_sender", description)
130
- # self.assertIn("registered_tools", description)
131
-
132
- # def test_merge_branch(self):
133
- # """Test merging another Branch instance into the current one."""
134
- # mes = [
135
- # {
136
- # "node_id": "6",
137
- # "timestamp": "2021-01-01 00:01:00",
138
- # "role": "user",
139
- # "sender": "user1",
140
- # "content": json.dumps({"instruction": "User message"}),
141
- # }
142
- # ]
143
- # other_branch = Branch(branch_name="OtherBranch", messages=pd.DataFrame(mes))
144
-
145
- # original_message_count = len(self.branch.messages)
146
- # self.branch.merge_branch(other_branch)
147
- # merged_message_count = len(self.branch.messages)
148
- # self.assertTrue(merged_message_count > original_message_count)
149
-
150
- # def test_register_and_delete_tools(self):
151
- # """Test tool registration and deletion."""
152
- # self.branch.register_tools(self.tool)
153
- # self.assertIn("sample_func", self.branch.tool_manager.registry)
154
- # self.branch.delete_tools(self.tool, verbose=False)
155
- # self.assertNotIn("sample_func", self.branch.tool_manager.registry)
156
-
157
- # def test_send(self):
158
- # """Test sending a mail package."""
159
- # package = {"data": "example"}
160
- # self.branch.send(recipient="BranchB", category="messages", package=package)
161
- # self.assertEqual(len(self.branch.pending_outs), 1)
162
- # mail = self.branch.pending_outs[0]
163
- # self.assertEqual(mail.sender, "system")
164
- # self.assertEqual(mail.recipient, "BranchB")
165
- # self.assertEqual(mail.category, "messages")
166
- # self.assertEqual(mail.package, package)
167
-
168
- # # def test_is_invoked_true(self):
169
- # # branch = Branch()
170
-
171
- # # mock_messages = [
172
- # # MessageUtil.to_json_content({"action_response": {"function": "func_name", "arguments": {}, "output": "result"}})
173
- # # ]
174
- # # branch.messages = pd.DataFrame(mock_messages, columns=['content'])
175
- # # self.assertTrue(branch._is_invoked())
176
-
177
- # def test_is_invoked_false(self):
178
- # """Test that _is_invoked returns False when the last message is not a valid action response."""
179
- # self.assertFalse(self.branch._is_invoked())
180
-
181
-
182
- # class TestBranchReceive(unittest.TestCase):
183
- # def setUp(self):
184
- # self.branch = Branch(branch_name="TestBranch")
185
- # # Set up a mock sender and initial pending_ins structure
186
- # self.sender = "MockSender"
187
- # self.branch.pending_ins[self.sender] = deque()
188
-
189
- # # @patch("lionagi.core.mail.BaseMail")
190
- # # @patch("lionagi.core.branch.util.MessageUtil.validate_messages")
191
- # # def test_receive_messages(self, mock_validate_messages, mock_base_mail):
192
- # # # Prepare a mock mail package with messages
193
- # # messages_df = pd.DataFrame(
194
- # # [
195
- # # {
196
- # # "node_id": "1",
197
- # # "timestamp": "2021-01-01 00:00:00",
198
- # # "role": "system",
199
- # # "sender": "system",
200
- # # "content": json.dumps({"system_info": "System message"}),
201
- # # }
202
- # # ]
203
- # # )
204
- # # mail_package_messages = MagicMock(category="messages", package=messages_df)
205
- # # self.branch.pending_ins[self.sender].append(mail_package_messages)
206
-
207
- # # # Test receiving messages
208
- # # self.branch.receive(self.sender)
209
- # # mock_validate_messages.assert_called_once_with(messages_df)
210
- # # self.assertTrue(len(self.branch.messages) > 0)
211
- # # self.assertEqual(self.branch.pending_ins, {})
212
-
213
- # # def test_receive_tools(self):
214
- # # def sample_func(param1: int) -> bool:
215
- # # """Sample function.
216
-
217
- # # Args:
218
- # # param1 (int): Description of param1.
219
-
220
- # # Returns:
221
- # # bool: Description of return value.
222
- # # """
223
- # # return True
224
-
225
- # # tool = func_to_tool(sample_func)
226
- # # mail_package_tools = MagicMock(category="tools", package=tool)
227
- # # self.branch.pending_ins[self.sender].append(mail_package_tools)
228
-
229
- # # # Test receiving tools
230
- # # self.branch.receive(self.sender)
231
- # # self.assertIn(tool, self.branch.tool_manager.registry.values())
232
-
233
- # def test_receive_service(self):
234
- # # Prepare a mock mail package with a service
235
- # from lionagi.libs.ln_api import BaseService
236
-
237
- # service = BaseService()
238
- # mail_package_service = MagicMock(category="provider", package=service)
239
- # self.branch.pending_ins[self.sender].append(mail_package_service)
240
-
241
- # # Test receiving service
242
- # self.branch.receive(self.sender)
243
- # self.assertEqual(self.branch.service, service)
244
-
245
- # def test_receive_llmconfig(self):
246
- # # Prepare a mock mail package with llmconfig
247
- # llmconfig = self.branch.llmconfig.copy()
248
- # mail_package_llmconfig = MagicMock(category="llmconfig", package=llmconfig)
249
- # self.branch.pending_ins[self.sender].append(mail_package_llmconfig)
250
-
251
- # # Test receiving llmconfig
252
- # self.branch.receive(self.sender)
253
- # self.assertEqual(llmconfig, self.branch.llmconfig)
254
-
255
- # def test_invalid_format(self):
256
- # # Test handling of invalid package format
257
- # invalid_package = MagicMock(category="messages", package="Not a DataFrame")
258
- # self.branch.pending_ins[self.sender].append(invalid_package)
259
-
260
- # with self.assertRaises(ValueError) as context:
261
- # self.branch.receive(self.sender)
262
- # self.assertTrue("Invalid messages format" in str(context.exception))
263
-
264
- # def test_receive_all(self):
265
- # messages_df = pd.DataFrame(
266
- # [
267
- # {
268
- # "node_id": "1",
269
- # "timestamp": "2021-01-01 00:00:00",
270
- # "role": "system",
271
- # "sender": "system",
272
- # "content": json.dumps({"system_info": "System message"}),
273
- # }
274
- # ]
275
- # )
276
- # mail_package_messages = MagicMock(category="messages", package=messages_df)
277
- # self.branch.pending_ins[self.sender].append(mail_package_messages)
278
-
279
- # llmconfig = self.branch.llmconfig.copy()
280
- # mail_package_llmconfig = MagicMock(category="llmconfig", package=llmconfig)
281
- # self.branch.pending_ins[self.sender].append(mail_package_llmconfig)
282
-
283
- # self.branch.receive_all()
284
- # self.assertTrue(
285
- # not self.branch.pending_ins,
286
- # "pending_ins should be empty or contain only skipped requests",
287
- # )
288
- # self.assertTrue(..., "Additional assertions based on your implementation")
289
-
290
-
291
- # # Chatflow: call_chatcompletion, chat, ReAct, auto_followup
292
-
293
- # if __name__ == "__main__":
294
- # unittest.main()
1
+ import unittest
2
+ from unittest.mock import MagicMock, patch
3
+ import lionagi as li
4
+ from lionagi.core.message import System, Instruction, AssistantResponse, ActionResponse
5
+ from lionagi.core.collections import Pile, Progression, Exchange
6
+ from lionagi.core.action.tool_manager import ToolManager
7
+
8
+
9
+ class TestBranch(unittest.TestCase):
10
+
11
+ def setUp(self):
12
+ self.branch = li.Branch()
13
+
14
+ def test_initialize_branch(self):
15
+ self.assertIsInstance(self.branch, li.Branch)
16
+ self.assertIsInstance(self.branch.messages, Pile)
17
+ self.assertIsInstance(self.branch.progress, Progression)
18
+ self.assertIsInstance(self.branch.tool_manager, ToolManager)
19
+ self.assertIsInstance(self.branch.mailbox, Exchange)
20
+ self.assertIsInstance(self.branch.imodel, li.iModel)
21
+
22
+ def test_add_message_system(self):
23
+ self.branch.add_message(
24
+ system="You are a helpful assistant, let's think step by step"
25
+ )
26
+ self.assertEqual(len(self.branch.messages), 1)
27
+ self.assertEqual(
28
+ self.branch.messages[0].content,
29
+ {"system_info": "You are a helpful assistant, let's think step by step"},
30
+ )
31
+
32
+ def test_to_df(self):
33
+ self.branch.add_message(
34
+ system="You are a helpful assistant, let's think step by step"
35
+ )
36
+ df = self.branch.to_df()
37
+ self.assertEqual(df.iloc[0]["message_type"], "System")
38
+ self.assertEqual(df.iloc[0]["role"], "system")
39
+
40
+ def test_to_chat_messages(self):
41
+ self.branch.add_message(
42
+ system="You are a helpful assistant, let's think step by step"
43
+ )
44
+ chat_msgs = self.branch.to_chat_messages()
45
+ self.assertEqual(chat_msgs[0]["role"], "system")
46
+ self.assertEqual(
47
+ chat_msgs[0]["content"],
48
+ "You are a helpful assistant, let's think step by step",
49
+ )
50
+
51
+ @patch("lionagi.Branch.chat")
52
+ async def test_chat(self, mock_chat):
53
+ mock_chat.return_value = (
54
+ "Rain poured, but their love shone brighter than any storm."
55
+ )
56
+ response = await self.branch.chat("tell me a 10 word story", logprobs=True)
57
+ self.assertEqual(
58
+ response, "Rain poured, but their love shone brighter than any storm."
59
+ )
60
+ mock_chat.assert_called_once_with("tell me a 10 word story", logprobs=True)
61
+
62
+ def test_metadata(self):
63
+ self.branch.add_message(
64
+ system="You are a helpful assistant, let's think step by step"
65
+ )
66
+ self.assertIn("last_updated", self.branch.messages[0].metadata)
67
+
68
+ # def test_register_tools(self):
69
+ # tool = MagicMock()
70
+ # self.branch.register_tools([tool])
71
+ # self.assertIn(tool, self.branch.tool_manager.registry.values())
72
+
73
+ # def test_delete_tools(self):
74
+ # tool = MagicMock()
75
+ # tool.schema_ = {"function": {"name": "test_tool"}}
76
+ # self.branch.register_tools([tool])
77
+ # self.branch.delete_tools([tool])
78
+ # self.assertNotIn("test_tool", self.branch.tool_manager.registry)
79
+
80
+ def test_send_receive_mail(self):
81
+ self.branch.send = MagicMock()
82
+ self.branch.receive = MagicMock()
83
+ package = MagicMock()
84
+ self.branch.send(recipient="recipient_id", category="message", package=package)
85
+ self.branch.receive(sender="recipient_id")
86
+ self.branch.send.assert_called_once_with(
87
+ recipient="recipient_id", category="message", package=package
88
+ )
89
+ self.branch.receive.assert_called_once_with(sender="recipient_id")
90
+
91
+ async def test_chat_with_tool(self):
92
+ async def mock_multiply(number1, number2, number3=1):
93
+ return number1 * number2 * number3
94
+
95
+ instruction = """
96
+ solve the following problem
97
+ """
98
+ context = """
99
+ I have 730_000 trees, with average 123 apples per tree, each weigh 0.4 lbs.
100
+ 20 percent are bad and sold for 0.1 dollar per lbs, 30 percent are sold to
101
+ brewery for 0.3 dollar per apple, what is my revenue?
102
+ """
103
+
104
+ self.branch = li.Branch(
105
+ "act like a calculator, invoke tool uses", tools=[mock_multiply]
106
+ )
107
+ response = await self.branch.chat(
108
+ instruction=instruction, context=context, tools=True
109
+ )
110
+ self.assertIsNotNone(response)
111
+ self.assertIn("revenue", response.lower())
112
+
113
+
114
+ if __name__ == "__main__":
115
+ unittest.main()
@@ -0,0 +1,46 @@
1
+ import unittest
2
+ from lionagi import Form
3
+
4
+
5
+ class TestForm(unittest.TestCase):
6
+
7
+ def setUp(self):
8
+ self.form = Form(assignment="input1, input2 -> output")
9
+
10
+ def test_initial_state(self):
11
+ self.assertEqual(self.form.input_fields, ["input1", "input2"])
12
+ self.assertEqual(self.form.requested_fields, ["output"])
13
+ self.assertFalse(self.form.workable)
14
+ self.assertFalse(self.form.filled)
15
+ self.assertEqual(
16
+ self.form.work_fields, {"input1": None, "input2": None, "output": None}
17
+ )
18
+
19
+ def test_fill_input_fields(self):
20
+ self.form.fill(input1=1, input2=2)
21
+ self.assertTrue(self.form.workable)
22
+ self.assertFalse(self.form.filled)
23
+ self.assertEqual(
24
+ self.form.work_fields, {"input1": 1, "input2": 2, "output": None}
25
+ )
26
+
27
+ def test_fill_all_fields(self):
28
+ self.form.fill(input1=1, input2=2)
29
+ self.form.fill(output=3)
30
+ self.assertTrue(self.form.filled)
31
+ self.assertFalse(self.form.workable)
32
+ self.assertEqual(self.form.work_fields, {"input1": 1, "input2": 2, "output": 3})
33
+
34
+ def test_fill_once(self):
35
+ self.form.fill(input1=1, input2=2)
36
+ self.form.fill(output=3)
37
+ with self.assertRaises(ValueError) as context:
38
+ self.form.fill(input1=2, input2=3)
39
+ self.assertTrue(
40
+ "Form is filled, cannot be worked on again" in str(context.exception)
41
+ )
42
+ self.assertEqual(self.form.work_fields, {"input1": 1, "input2": 2, "output": 3})
43
+
44
+
45
+ if __name__ == "__main__":
46
+ unittest.main()
@@ -0,0 +1,105 @@
1
+ import unittest
2
+ from lionagi.core.report.form import Form
3
+ from lionagi.core.report.report import Report
4
+
5
+
6
+ class TestForm(unittest.TestCase):
7
+
8
+ def setUp(self):
9
+ self.form = Form(assignment="input1, input2 -> output")
10
+
11
+ def test_initial_fields(self):
12
+ self.assertEqual(self.form.input_fields, ["input1", "input2"])
13
+ self.assertEqual(self.form.requested_fields, ["output"])
14
+ self.assertFalse(self.form.workable)
15
+ self.assertFalse(self.form.filled)
16
+ self.assertEqual(
17
+ self.form.work_fields, {"input1": None, "input2": None, "output": None}
18
+ )
19
+
20
+ def test_fill_input_fields(self):
21
+ self.form.fill(input1=1, input2=2)
22
+ self.assertTrue(self.form.workable)
23
+ self.assertFalse(self.form.filled)
24
+ self.assertEqual(
25
+ self.form.work_fields, {"input1": 1, "input2": 2, "output": None}
26
+ )
27
+
28
+ def test_fill_output_field(self):
29
+ self.form.fill(input1=1, input2=2)
30
+ self.form.fill(output=3)
31
+ self.assertTrue(self.form.filled)
32
+ self.assertEqual(self.form.work_fields, {"input1": 1, "input2": 2, "output": 3})
33
+ self.assertFalse(self.form.workable)
34
+
35
+ def test_fill_again_raises_error(self):
36
+ self.form.fill(input1=1, input2=2, output=3)
37
+ with self.assertRaises(ValueError):
38
+ self.form.fill(input1=2, input2=3)
39
+
40
+
41
+ class TestReport(unittest.TestCase):
42
+
43
+ def setUp(self):
44
+ self.report = Report(assignment="a, b -> c")
45
+
46
+ def test_initial_fields(self):
47
+ self.assertEqual(self.report.input_fields, ["a", "b"])
48
+ self.assertEqual(self.report.requested_fields, ["c"])
49
+ self.assertEqual(self.report.work_fields, {"a": None, "b": None, "c": None})
50
+ self.assertFalse(self.report.filled)
51
+ self.assertFalse(self.report.workable)
52
+
53
+ def test_fill_input_fields(self):
54
+ self.report.fill(a=3, b=4)
55
+ self.assertEqual(self.report.work_fields, {"a": 3, "b": 4, "c": None})
56
+ self.assertTrue(self.report.workable)
57
+
58
+ def test_fill_output_field(self):
59
+ self.report.fill(a=3, b=4)
60
+ self.report.fill(c=4)
61
+ self.assertEqual(self.report.work_fields, {"a": 3, "b": 4, "c": 4})
62
+ self.assertTrue(self.report.filled)
63
+ self.assertFalse(self.report.workable)
64
+
65
+ def test_next_forms_none(self):
66
+ self.assertIsNone(self.report.next_forms())
67
+
68
+ def test_complex_assignment(self):
69
+ self.report = Report(
70
+ assignment="a, b -> h",
71
+ form_assignments=[
72
+ "a, b -> c",
73
+ "a -> e",
74
+ "b -> f",
75
+ "c -> g",
76
+ "e, f, g -> h",
77
+ ],
78
+ a=3,
79
+ b=4,
80
+ )
81
+ self.assertEqual(
82
+ self.report.work_fields,
83
+ {
84
+ "a": None,
85
+ "b": None,
86
+ "c": None,
87
+ "e": None,
88
+ "f": None,
89
+ "g": None,
90
+ "h": None,
91
+ },
92
+ )
93
+ self.report.fill(c=5, e=6, f=7, g=8, h=10)
94
+ self.assertEqual(
95
+ self.report.work_fields,
96
+ {"a": None, "b": None, "c": 5, "e": 6, "f": 7, "g": 8, "h": 10},
97
+ )
98
+ self.assertFalse(self.report.filled)
99
+ self.assertFalse(self.report.workable)
100
+ with self.assertRaises(ValueError):
101
+ self.report.fill(c="xx", e="yy")
102
+
103
+
104
+ if __name__ == "__main__":
105
+ unittest.main()