lionagi 0.0.312__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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()
|