lionagi 0.0.312__py3-none-any.whl → 0.2.1__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- lionagi/__init__.py +61 -3
- lionagi/core/__init__.py +0 -14
- lionagi/core/_setting/_setting.py +59 -0
- lionagi/core/action/__init__.py +14 -0
- lionagi/core/action/function_calling.py +136 -0
- lionagi/core/action/manual.py +1 -0
- lionagi/core/action/node.py +109 -0
- lionagi/core/action/tool.py +114 -0
- lionagi/core/action/tool_manager.py +356 -0
- lionagi/core/agent/__init__.py +0 -3
- lionagi/core/agent/base_agent.py +45 -36
- lionagi/core/agent/eval/evaluator.py +1 -0
- lionagi/core/agent/eval/vote.py +40 -0
- lionagi/core/agent/learn/learner.py +59 -0
- lionagi/core/agent/plan/unit_template.py +1 -0
- lionagi/core/collections/__init__.py +17 -0
- lionagi/core/collections/_logger.py +319 -0
- lionagi/core/collections/abc/__init__.py +53 -0
- lionagi/core/collections/abc/component.py +615 -0
- lionagi/core/collections/abc/concepts.py +297 -0
- lionagi/core/collections/abc/exceptions.py +150 -0
- lionagi/core/collections/abc/util.py +45 -0
- lionagi/core/collections/exchange.py +161 -0
- lionagi/core/collections/flow.py +426 -0
- lionagi/core/collections/model.py +419 -0
- lionagi/core/collections/pile.py +913 -0
- lionagi/core/collections/progression.py +236 -0
- lionagi/core/collections/util.py +64 -0
- lionagi/core/director/direct.py +314 -0
- lionagi/core/director/director.py +2 -0
- lionagi/core/engine/branch_engine.py +333 -0
- lionagi/core/engine/instruction_map_engine.py +204 -0
- lionagi/core/engine/sandbox_.py +14 -0
- lionagi/core/engine/script_engine.py +99 -0
- lionagi/core/executor/base_executor.py +90 -0
- lionagi/core/executor/graph_executor.py +330 -0
- lionagi/core/executor/neo4j_executor.py +384 -0
- lionagi/core/generic/__init__.py +7 -0
- lionagi/core/generic/edge.py +112 -0
- lionagi/core/generic/edge_condition.py +16 -0
- lionagi/core/generic/graph.py +236 -0
- lionagi/core/generic/hyperedge.py +1 -0
- lionagi/core/generic/node.py +220 -0
- lionagi/core/generic/tree.py +48 -0
- lionagi/core/generic/tree_node.py +79 -0
- lionagi/core/mail/__init__.py +7 -3
- lionagi/core/mail/mail.py +25 -0
- lionagi/core/mail/mail_manager.py +142 -58
- lionagi/core/mail/package.py +45 -0
- lionagi/core/mail/start_mail.py +36 -0
- lionagi/core/message/__init__.py +19 -0
- lionagi/core/message/action_request.py +133 -0
- lionagi/core/message/action_response.py +135 -0
- lionagi/core/message/assistant_response.py +95 -0
- lionagi/core/message/instruction.py +234 -0
- lionagi/core/message/message.py +101 -0
- lionagi/core/message/system.py +86 -0
- lionagi/core/message/util.py +283 -0
- lionagi/core/report/__init__.py +4 -0
- lionagi/core/report/base.py +217 -0
- lionagi/core/report/form.py +231 -0
- lionagi/core/report/report.py +166 -0
- lionagi/core/report/util.py +28 -0
- lionagi/core/rule/__init__.py +0 -0
- lionagi/core/rule/_default.py +16 -0
- lionagi/core/rule/action.py +99 -0
- lionagi/core/rule/base.py +238 -0
- lionagi/core/rule/boolean.py +56 -0
- lionagi/core/rule/choice.py +47 -0
- lionagi/core/rule/mapping.py +96 -0
- lionagi/core/rule/number.py +71 -0
- lionagi/core/rule/rulebook.py +109 -0
- lionagi/core/rule/string.py +52 -0
- lionagi/core/rule/util.py +35 -0
- lionagi/core/session/__init__.py +0 -3
- lionagi/core/session/branch.py +431 -0
- lionagi/core/session/directive_mixin.py +287 -0
- lionagi/core/session/session.py +230 -902
- lionagi/core/structure/__init__.py +1 -0
- lionagi/core/structure/chain.py +1 -0
- lionagi/core/structure/forest.py +1 -0
- lionagi/core/structure/graph.py +1 -0
- lionagi/core/structure/tree.py +1 -0
- lionagi/core/unit/__init__.py +5 -0
- lionagi/core/unit/parallel_unit.py +245 -0
- lionagi/core/unit/template/__init__.py +0 -0
- lionagi/core/unit/template/action.py +81 -0
- lionagi/core/unit/template/base.py +51 -0
- lionagi/core/unit/template/plan.py +84 -0
- lionagi/core/unit/template/predict.py +109 -0
- lionagi/core/unit/template/score.py +124 -0
- lionagi/core/unit/template/select.py +104 -0
- lionagi/core/unit/unit.py +362 -0
- lionagi/core/unit/unit_form.py +305 -0
- lionagi/core/unit/unit_mixin.py +1168 -0
- lionagi/core/unit/util.py +71 -0
- lionagi/core/validator/__init__.py +0 -0
- lionagi/core/validator/validator.py +364 -0
- lionagi/core/work/__init__.py +0 -0
- lionagi/core/work/work.py +76 -0
- lionagi/core/work/work_function.py +101 -0
- lionagi/core/work/work_queue.py +103 -0
- lionagi/core/work/worker.py +258 -0
- lionagi/core/work/worklog.py +120 -0
- lionagi/experimental/__init__.py +0 -0
- lionagi/experimental/compressor/__init__.py +0 -0
- lionagi/experimental/compressor/base.py +46 -0
- lionagi/experimental/compressor/llm_compressor.py +247 -0
- lionagi/experimental/compressor/llm_summarizer.py +61 -0
- lionagi/experimental/compressor/util.py +70 -0
- lionagi/experimental/directive/__init__.py +19 -0
- lionagi/experimental/directive/parser/__init__.py +0 -0
- lionagi/experimental/directive/parser/base_parser.py +282 -0
- lionagi/experimental/directive/template/__init__.py +0 -0
- lionagi/experimental/directive/template/base_template.py +79 -0
- lionagi/experimental/directive/template/schema.py +36 -0
- lionagi/experimental/directive/tokenizer.py +73 -0
- lionagi/experimental/evaluator/__init__.py +0 -0
- lionagi/experimental/evaluator/ast_evaluator.py +131 -0
- lionagi/experimental/evaluator/base_evaluator.py +218 -0
- lionagi/experimental/knowledge/__init__.py +0 -0
- lionagi/experimental/knowledge/base.py +10 -0
- lionagi/experimental/knowledge/graph.py +0 -0
- lionagi/experimental/memory/__init__.py +0 -0
- lionagi/experimental/strategies/__init__.py +0 -0
- lionagi/experimental/strategies/base.py +1 -0
- lionagi/integrations/bridge/autogen_/__init__.py +0 -0
- lionagi/integrations/bridge/autogen_/autogen_.py +124 -0
- lionagi/integrations/bridge/langchain_/documents.py +4 -0
- lionagi/integrations/bridge/llamaindex_/index.py +30 -0
- lionagi/integrations/bridge/llamaindex_/llama_index_bridge.py +6 -0
- lionagi/integrations/bridge/llamaindex_/llama_pack.py +227 -0
- lionagi/integrations/bridge/llamaindex_/node_parser.py +6 -9
- lionagi/integrations/bridge/pydantic_/pydantic_bridge.py +1 -0
- lionagi/integrations/bridge/transformers_/__init__.py +0 -0
- lionagi/integrations/bridge/transformers_/install_.py +36 -0
- lionagi/integrations/chunker/__init__.py +0 -0
- lionagi/integrations/chunker/chunk.py +312 -0
- lionagi/integrations/config/oai_configs.py +38 -7
- lionagi/integrations/config/ollama_configs.py +1 -1
- lionagi/integrations/config/openrouter_configs.py +14 -2
- lionagi/integrations/loader/__init__.py +0 -0
- lionagi/integrations/loader/load.py +253 -0
- lionagi/integrations/loader/load_util.py +195 -0
- lionagi/integrations/provider/_mapping.py +46 -0
- lionagi/integrations/provider/litellm.py +2 -1
- lionagi/integrations/provider/mlx_service.py +16 -9
- lionagi/integrations/provider/oai.py +91 -4
- lionagi/integrations/provider/ollama.py +7 -6
- lionagi/integrations/provider/openrouter.py +115 -8
- lionagi/integrations/provider/services.py +2 -2
- lionagi/integrations/provider/transformers.py +18 -22
- lionagi/integrations/storage/__init__.py +3 -0
- lionagi/integrations/storage/neo4j.py +665 -0
- lionagi/integrations/storage/storage_util.py +287 -0
- lionagi/integrations/storage/structure_excel.py +285 -0
- lionagi/integrations/storage/to_csv.py +63 -0
- lionagi/integrations/storage/to_excel.py +83 -0
- lionagi/libs/__init__.py +26 -1
- lionagi/libs/ln_api.py +78 -23
- lionagi/libs/ln_context.py +37 -0
- lionagi/libs/ln_convert.py +21 -9
- lionagi/libs/ln_func_call.py +69 -28
- lionagi/libs/ln_image.py +107 -0
- lionagi/libs/ln_knowledge_graph.py +405 -0
- lionagi/libs/ln_nested.py +26 -11
- lionagi/libs/ln_parse.py +110 -14
- lionagi/libs/ln_queue.py +117 -0
- lionagi/libs/ln_tokenize.py +164 -0
- lionagi/{core/prompt/field_validator.py → libs/ln_validate.py} +79 -14
- lionagi/libs/special_tokens.py +172 -0
- lionagi/libs/sys_util.py +107 -2
- lionagi/lions/__init__.py +0 -0
- lionagi/lions/coder/__init__.py +0 -0
- lionagi/lions/coder/add_feature.py +20 -0
- lionagi/lions/coder/base_prompts.py +22 -0
- lionagi/lions/coder/code_form.py +13 -0
- lionagi/lions/coder/coder.py +168 -0
- lionagi/lions/coder/util.py +96 -0
- lionagi/lions/researcher/__init__.py +0 -0
- lionagi/lions/researcher/data_source/__init__.py +0 -0
- lionagi/lions/researcher/data_source/finhub_.py +191 -0
- lionagi/lions/researcher/data_source/google_.py +199 -0
- lionagi/lions/researcher/data_source/wiki_.py +96 -0
- lionagi/lions/researcher/data_source/yfinance_.py +21 -0
- lionagi/tests/integrations/__init__.py +0 -0
- lionagi/tests/libs/__init__.py +0 -0
- lionagi/tests/libs/test_field_validators.py +353 -0
- lionagi/tests/{test_libs → libs}/test_func_call.py +23 -21
- lionagi/tests/{test_libs → libs}/test_nested.py +36 -21
- lionagi/tests/{test_libs → libs}/test_parse.py +1 -1
- lionagi/tests/libs/test_queue.py +67 -0
- lionagi/tests/test_core/collections/__init__.py +0 -0
- lionagi/tests/test_core/collections/test_component.py +206 -0
- lionagi/tests/test_core/collections/test_exchange.py +138 -0
- lionagi/tests/test_core/collections/test_flow.py +145 -0
- lionagi/tests/test_core/collections/test_pile.py +171 -0
- lionagi/tests/test_core/collections/test_progression.py +129 -0
- lionagi/tests/test_core/generic/__init__.py +0 -0
- lionagi/tests/test_core/generic/test_edge.py +67 -0
- lionagi/tests/test_core/generic/test_graph.py +96 -0
- lionagi/tests/test_core/generic/test_node.py +106 -0
- lionagi/tests/test_core/generic/test_tree_node.py +73 -0
- lionagi/tests/test_core/test_branch.py +115 -292
- lionagi/tests/test_core/test_form.py +46 -0
- lionagi/tests/test_core/test_report.py +105 -0
- lionagi/tests/test_core/test_validator.py +111 -0
- lionagi/version.py +1 -1
- {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/LICENSE +12 -11
- {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/METADATA +19 -118
- lionagi-0.2.1.dist-info/RECORD +240 -0
- lionagi/core/branch/__init__.py +0 -4
- lionagi/core/branch/base_branch.py +0 -654
- lionagi/core/branch/branch.py +0 -471
- lionagi/core/branch/branch_flow_mixin.py +0 -96
- lionagi/core/branch/executable_branch.py +0 -347
- lionagi/core/branch/util.py +0 -323
- lionagi/core/direct/__init__.py +0 -6
- lionagi/core/direct/predict.py +0 -161
- lionagi/core/direct/score.py +0 -278
- lionagi/core/direct/select.py +0 -169
- lionagi/core/direct/utils.py +0 -87
- lionagi/core/direct/vote.py +0 -64
- lionagi/core/flow/base/baseflow.py +0 -23
- lionagi/core/flow/monoflow/ReAct.py +0 -238
- lionagi/core/flow/monoflow/__init__.py +0 -9
- lionagi/core/flow/monoflow/chat.py +0 -95
- lionagi/core/flow/monoflow/chat_mixin.py +0 -263
- lionagi/core/flow/monoflow/followup.py +0 -214
- lionagi/core/flow/polyflow/__init__.py +0 -1
- lionagi/core/flow/polyflow/chat.py +0 -248
- lionagi/core/mail/schema.py +0 -56
- lionagi/core/messages/__init__.py +0 -3
- lionagi/core/messages/schema.py +0 -533
- lionagi/core/prompt/prompt_template.py +0 -316
- lionagi/core/schema/__init__.py +0 -22
- lionagi/core/schema/action_node.py +0 -29
- lionagi/core/schema/base_mixin.py +0 -296
- lionagi/core/schema/base_node.py +0 -199
- lionagi/core/schema/condition.py +0 -24
- lionagi/core/schema/data_logger.py +0 -354
- lionagi/core/schema/data_node.py +0 -93
- lionagi/core/schema/prompt_template.py +0 -67
- lionagi/core/schema/structure.py +0 -910
- lionagi/core/tool/__init__.py +0 -3
- lionagi/core/tool/tool_manager.py +0 -280
- lionagi/integrations/bridge/pydantic_/base_model.py +0 -7
- lionagi/tests/test_core/test_base_branch.py +0 -427
- lionagi/tests/test_core/test_chat_flow.py +0 -63
- lionagi/tests/test_core/test_mail_manager.py +0 -75
- lionagi/tests/test_core/test_prompts.py +0 -51
- lionagi/tests/test_core/test_session.py +0 -254
- lionagi/tests/test_core/test_session_base_util.py +0 -312
- lionagi/tests/test_core/test_tool_manager.py +0 -95
- lionagi-0.0.312.dist-info/RECORD +0 -111
- /lionagi/core/{branch/base → _setting}/__init__.py +0 -0
- /lionagi/core/{flow → agent/eval}/__init__.py +0 -0
- /lionagi/core/{flow/base → agent/learn}/__init__.py +0 -0
- /lionagi/core/{prompt → agent/plan}/__init__.py +0 -0
- /lionagi/core/{tool/manual.py → agent/plan/plan.py} +0 -0
- /lionagi/{tests/test_integrations → core/director}/__init__.py +0 -0
- /lionagi/{tests/test_libs → core/engine}/__init__.py +0 -0
- /lionagi/{tests/test_libs/test_async.py → core/executor/__init__.py} +0 -0
- /lionagi/tests/{test_libs → libs}/test_api.py +0 -0
- /lionagi/tests/{test_libs → libs}/test_convert.py +0 -0
- /lionagi/tests/{test_libs → libs}/test_sys_util.py +0 -0
- {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/WHEEL +0 -0
- {lionagi-0.0.312.dist-info → lionagi-0.2.1.dist-info}/top_level.txt +0 -0
@@ -1,292 +1,115 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
#
|
70
|
-
|
71
|
-
#
|
72
|
-
|
73
|
-
#
|
74
|
-
#
|
75
|
-
#
|
76
|
-
#
|
77
|
-
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
# # datalogger=None,
|
117
|
-
# # persist_path=None,
|
118
|
-
# # tool_manager=None,
|
119
|
-
# # )
|
120
|
-
|
121
|
-
# def test_messages_describe(self):
|
122
|
-
# """Test the messages_describe method for accuracy."""
|
123
|
-
# # Assuming self.branch has been set up with some messages
|
124
|
-
# description = self.branch.messages_describe()
|
125
|
-
# self.assertIn("total_messages", description)
|
126
|
-
# self.assertIn("summary_by_role", description)
|
127
|
-
# self.assertIn("summary_by_sender", description)
|
128
|
-
# self.assertIn("registered_tools", description)
|
129
|
-
|
130
|
-
# def test_merge_branch(self):
|
131
|
-
# """Test merging another Branch instance into the current one."""
|
132
|
-
# mes = [
|
133
|
-
# {
|
134
|
-
# "node_id": "6",
|
135
|
-
# "timestamp": "2021-01-01 00:01:00",
|
136
|
-
# "role": "user",
|
137
|
-
# "sender": "user1",
|
138
|
-
# "content": json.dumps({"instruction": "User message"}),
|
139
|
-
# }
|
140
|
-
# ]
|
141
|
-
# other_branch = Branch(branch_name="OtherBranch", messages=pd.DataFrame(mes))
|
142
|
-
|
143
|
-
# original_message_count = len(self.branch.messages)
|
144
|
-
# self.branch.merge_branch(other_branch)
|
145
|
-
# merged_message_count = len(self.branch.messages)
|
146
|
-
# self.assertTrue(merged_message_count > original_message_count)
|
147
|
-
|
148
|
-
# def test_register_and_delete_tools(self):
|
149
|
-
# """Test tool registration and deletion."""
|
150
|
-
# self.branch.register_tools(self.tool)
|
151
|
-
# self.assertIn("sample_func", self.branch.tool_manager.registry)
|
152
|
-
# self.branch.delete_tools(self.tool, verbose=False)
|
153
|
-
# self.assertNotIn("sample_func", self.branch.tool_manager.registry)
|
154
|
-
|
155
|
-
# def test_send(self):
|
156
|
-
# """Test sending a mail package."""
|
157
|
-
# package = {"data": "example"}
|
158
|
-
# self.branch.send(recipient="BranchB", category="messages", package=package)
|
159
|
-
# self.assertEqual(len(self.branch.pending_outs), 1)
|
160
|
-
# mail = self.branch.pending_outs[0]
|
161
|
-
# self.assertEqual(mail.sender, "system")
|
162
|
-
# self.assertEqual(mail.recipient, "BranchB")
|
163
|
-
# self.assertEqual(mail.category, "messages")
|
164
|
-
# self.assertEqual(mail.package, package)
|
165
|
-
|
166
|
-
# # def test_is_invoked_true(self):
|
167
|
-
# # branch = Branch()
|
168
|
-
|
169
|
-
# # mock_messages = [
|
170
|
-
# # MessageUtil.to_json_content({"action_response": {"function": "func_name", "arguments": {}, "output": "result"}})
|
171
|
-
# # ]
|
172
|
-
# # branch.messages = pd.DataFrame(mock_messages, columns=['content'])
|
173
|
-
# # self.assertTrue(branch._is_invoked())
|
174
|
-
|
175
|
-
# def test_is_invoked_false(self):
|
176
|
-
# """Test that _is_invoked returns False when the last message is not a valid action response."""
|
177
|
-
# self.assertFalse(self.branch._is_invoked())
|
178
|
-
|
179
|
-
|
180
|
-
# class TestBranchReceive(unittest.TestCase):
|
181
|
-
# def setUp(self):
|
182
|
-
# self.branch = Branch(branch_name="TestBranch")
|
183
|
-
# # Set up a mock sender and initial pending_ins structure
|
184
|
-
# self.sender = "MockSender"
|
185
|
-
# self.branch.pending_ins[self.sender] = deque()
|
186
|
-
|
187
|
-
# # @patch("lionagi.core.mail.BaseMail")
|
188
|
-
# # @patch("lionagi.core.branch.util.MessageUtil.validate_messages")
|
189
|
-
# # def test_receive_messages(self, mock_validate_messages, mock_base_mail):
|
190
|
-
# # # Prepare a mock mail package with messages
|
191
|
-
# # messages_df = pd.DataFrame(
|
192
|
-
# # [
|
193
|
-
# # {
|
194
|
-
# # "node_id": "1",
|
195
|
-
# # "timestamp": "2021-01-01 00:00:00",
|
196
|
-
# # "role": "system",
|
197
|
-
# # "sender": "system",
|
198
|
-
# # "content": json.dumps({"system_info": "System message"}),
|
199
|
-
# # }
|
200
|
-
# # ]
|
201
|
-
# # )
|
202
|
-
# # mail_package_messages = MagicMock(category="messages", package=messages_df)
|
203
|
-
# # self.branch.pending_ins[self.sender].append(mail_package_messages)
|
204
|
-
|
205
|
-
# # # Test receiving messages
|
206
|
-
# # self.branch.receive(self.sender)
|
207
|
-
# # mock_validate_messages.assert_called_once_with(messages_df)
|
208
|
-
# # self.assertTrue(len(self.branch.messages) > 0)
|
209
|
-
# # self.assertEqual(self.branch.pending_ins, {})
|
210
|
-
|
211
|
-
# # def test_receive_tools(self):
|
212
|
-
# # def sample_func(param1: int) -> bool:
|
213
|
-
# # """Sample function.
|
214
|
-
|
215
|
-
# # Args:
|
216
|
-
# # param1 (int): Description of param1.
|
217
|
-
|
218
|
-
# # Returns:
|
219
|
-
# # bool: Description of return value.
|
220
|
-
# # """
|
221
|
-
# # return True
|
222
|
-
|
223
|
-
# # tool = func_to_tool(sample_func)
|
224
|
-
# # mail_package_tools = MagicMock(category="tools", package=tool)
|
225
|
-
# # self.branch.pending_ins[self.sender].append(mail_package_tools)
|
226
|
-
|
227
|
-
# # # Test receiving tools
|
228
|
-
# # self.branch.receive(self.sender)
|
229
|
-
# # self.assertIn(tool, self.branch.tool_manager.registry.values())
|
230
|
-
|
231
|
-
# def test_receive_service(self):
|
232
|
-
# # Prepare a mock mail package with a service
|
233
|
-
# from lionagi.libs.ln_api import BaseService
|
234
|
-
|
235
|
-
# service = BaseService()
|
236
|
-
# mail_package_service = MagicMock(category="provider", package=service)
|
237
|
-
# self.branch.pending_ins[self.sender].append(mail_package_service)
|
238
|
-
|
239
|
-
# # Test receiving service
|
240
|
-
# self.branch.receive(self.sender)
|
241
|
-
# self.assertEqual(self.branch.service, service)
|
242
|
-
|
243
|
-
# def test_receive_llmconfig(self):
|
244
|
-
# # Prepare a mock mail package with llmconfig
|
245
|
-
# llmconfig = self.branch.llmconfig.copy()
|
246
|
-
# mail_package_llmconfig = MagicMock(category="llmconfig", package=llmconfig)
|
247
|
-
# self.branch.pending_ins[self.sender].append(mail_package_llmconfig)
|
248
|
-
|
249
|
-
# # Test receiving llmconfig
|
250
|
-
# self.branch.receive(self.sender)
|
251
|
-
# self.assertEqual(llmconfig, self.branch.llmconfig)
|
252
|
-
|
253
|
-
# def test_invalid_format(self):
|
254
|
-
# # Test handling of invalid package format
|
255
|
-
# invalid_package = MagicMock(category="messages", package="Not a DataFrame")
|
256
|
-
# self.branch.pending_ins[self.sender].append(invalid_package)
|
257
|
-
|
258
|
-
# with self.assertRaises(ValueError) as context:
|
259
|
-
# self.branch.receive(self.sender)
|
260
|
-
# self.assertTrue("Invalid messages format" in str(context.exception))
|
261
|
-
|
262
|
-
# def test_receive_all(self):
|
263
|
-
# messages_df = pd.DataFrame(
|
264
|
-
# [
|
265
|
-
# {
|
266
|
-
# "node_id": "1",
|
267
|
-
# "timestamp": "2021-01-01 00:00:00",
|
268
|
-
# "role": "system",
|
269
|
-
# "sender": "system",
|
270
|
-
# "content": json.dumps({"system_info": "System message"}),
|
271
|
-
# }
|
272
|
-
# ]
|
273
|
-
# )
|
274
|
-
# mail_package_messages = MagicMock(category="messages", package=messages_df)
|
275
|
-
# self.branch.pending_ins[self.sender].append(mail_package_messages)
|
276
|
-
|
277
|
-
# llmconfig = self.branch.llmconfig.copy()
|
278
|
-
# mail_package_llmconfig = MagicMock(category="llmconfig", package=llmconfig)
|
279
|
-
# self.branch.pending_ins[self.sender].append(mail_package_llmconfig)
|
280
|
-
|
281
|
-
# self.branch.receive_all()
|
282
|
-
# self.assertTrue(
|
283
|
-
# not self.branch.pending_ins,
|
284
|
-
# "pending_ins should be empty or contain only skipped requests",
|
285
|
-
# )
|
286
|
-
# self.assertTrue(..., "Additional assertions based on your implementation")
|
287
|
-
|
288
|
-
|
289
|
-
# # Chatflow: call_chatcompletion, chat, ReAct, auto_followup
|
290
|
-
|
291
|
-
# if __name__ == "__main__":
|
292
|
-
# 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()
|
@@ -0,0 +1,111 @@
|
|
1
|
+
import unittest
|
2
|
+
from typing import Dict, List, Any
|
3
|
+
from lionagi.core.report.form import Form
|
4
|
+
from lionagi.core.report.report import Report
|
5
|
+
from lionagi.core.collections.abc import FieldError
|
6
|
+
from lionagi.core.rule.base import Rule
|
7
|
+
from lionagi.core.rule.rulebook import RuleBook
|
8
|
+
from lionagi.core.validator.validator import (
|
9
|
+
Validator,
|
10
|
+
_DEFAULT_RULEORDER,
|
11
|
+
_DEFAULT_RULES,
|
12
|
+
)
|
13
|
+
|
14
|
+
|
15
|
+
class MockRule(Rule):
|
16
|
+
def applies(self, *args, **kwargs):
|
17
|
+
return True
|
18
|
+
|
19
|
+
async def invoke(self, field, value, form, *args, **kwargs):
|
20
|
+
if isinstance(value, int) and value < 0:
|
21
|
+
raise ValueError(f"Field {field} cannot be negative.")
|
22
|
+
return value
|
23
|
+
|
24
|
+
async def validate(self, value: Any) -> Any:
|
25
|
+
return value
|
26
|
+
|
27
|
+
|
28
|
+
class ValidatorTestCase(unittest.TestCase):
|
29
|
+
def setUp(self):
|
30
|
+
self.validator = Validator(
|
31
|
+
rulebook=RuleBook(rules=_DEFAULT_RULES, ruleorder=_DEFAULT_RULEORDER)
|
32
|
+
)
|
33
|
+
self.form = Form(
|
34
|
+
assignment="input1, input2 -> output",
|
35
|
+
input_fields=["input1", "input2"],
|
36
|
+
requested_fields=["output"],
|
37
|
+
)
|
38
|
+
self.form2 = Form(
|
39
|
+
assignment="total_amount, bike_price -> repair_price",
|
40
|
+
input_fields=["total_amount", "bike_price"],
|
41
|
+
requested_fields=["repair_price"],
|
42
|
+
)
|
43
|
+
|
44
|
+
def test_initiate_rules(self):
|
45
|
+
self.assertTrue(isinstance(self.validator.active_rules, dict))
|
46
|
+
|
47
|
+
async def test_validate_field(self):
|
48
|
+
self.validator.add_rule("mock_rule", MockRule)
|
49
|
+
valid_value = await self.validator.validate_field("input1", 10, self.form)
|
50
|
+
self.assertEqual(valid_value, 10)
|
51
|
+
|
52
|
+
with self.assertRaises(FieldError):
|
53
|
+
await self.validator.validate_field("input1", -5, self.form)
|
54
|
+
|
55
|
+
async def test_validate_response(self):
|
56
|
+
response = {"output": 20}
|
57
|
+
validated_form = await self.validator.validate_response(self.form, response)
|
58
|
+
self.assertEqual(validated_form.output, 20)
|
59
|
+
|
60
|
+
response_str = "20"
|
61
|
+
self.form.requested_fields = ["output"]
|
62
|
+
validated_form = await self.validator.validate_response(self.form, response_str)
|
63
|
+
self.assertEqual(validated_form.output, 20)
|
64
|
+
|
65
|
+
with self.assertRaises(ValueError):
|
66
|
+
await self.validator.validate_response(self.form, "invalid_response")
|
67
|
+
|
68
|
+
async def test_validate_report(self):
|
69
|
+
report = Report(assignment="a, b -> c", forms=[self.form])
|
70
|
+
forms = [self.form, self.form2]
|
71
|
+
validated_report = await self.validator.validate_report(report, forms)
|
72
|
+
self.assertIsInstance(validated_report, Report)
|
73
|
+
|
74
|
+
def test_add_rule(self):
|
75
|
+
self.validator.add_rule("mock_rule", MockRule)
|
76
|
+
self.assertIn("mock_rule", self.validator.active_rules)
|
77
|
+
|
78
|
+
def test_remove_rule(self):
|
79
|
+
self.validator.remove_rule("mock_rule")
|
80
|
+
self.assertNotIn("mock_rule", self.validator.active_rules)
|
81
|
+
|
82
|
+
def test_enable_rule(self):
|
83
|
+
self.validator.enable_rule("mock_rule", enable=False)
|
84
|
+
self.assertFalse(self.validator.active_rules["mock_rule"].enabled)
|
85
|
+
self.validator.enable_rule("mock_rule", enable=True)
|
86
|
+
self.assertTrue(self.validator.active_rules["mock_rule"].enabled)
|
87
|
+
|
88
|
+
def test_disable_rule(self):
|
89
|
+
self.validator.disable_rule("mock_rule")
|
90
|
+
self.assertFalse(self.validator.active_rules["mock_rule"].enabled)
|
91
|
+
|
92
|
+
def test_log_validation_attempt(self):
|
93
|
+
result = {"output": 20}
|
94
|
+
self.validator.log_validation_attempt(self.form, result)
|
95
|
+
self.assertEqual(len(self.validator.validation_log), 1)
|
96
|
+
|
97
|
+
def test_log_validation_error(self):
|
98
|
+
self.validator.log_validation_error("input1", 10, "Error message")
|
99
|
+
self.assertEqual(len(self.validator.validation_log), 1)
|
100
|
+
|
101
|
+
def test_get_validation_summary(self):
|
102
|
+
self.validator.log_validation_attempt(self.form, {"output": 20})
|
103
|
+
self.validator.log_validation_error("input1", 10, "Error message")
|
104
|
+
summary = self.validator.get_validation_summary()
|
105
|
+
self.assertEqual(summary["total_attempts"], 2)
|
106
|
+
self.assertEqual(len(summary["errors"]), 1)
|
107
|
+
self.assertEqual(len(summary["successful_attempts"]), 1)
|
108
|
+
|
109
|
+
|
110
|
+
if __name__ == "__main__":
|
111
|
+
unittest.main()
|